//	hdu 2846 Repository 字典树
//
//	题目大意:
//		
//		有n个字符串,m个待询问的字符串,问这些字符串里面以该询问的
//		字符串为子串的字符串有多少个
//
//	解题思路:
//		
//		字典树,将字符串的所有子串插入到字典树中,并设立一个No.标识
//		以免重计数。最后查询就好了
//
//	感悟:
//		
//		这题的数据量有点大,虽然p是10000,但是长度是20,单个字符串的
//		最大子串数粗略的估计是 20 * 20 ,所以开的空间也要比较大。开始
//		开的是30w,返回了wa,开了40w,还是返回wa,开了50w,结果轻松Ac
//		啦~,继续加油哟~~~FIGHTING
	
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAX_N = 500000;
struct Trie{
	int ch[MAX_N][26];
	int sz;
	int val[MAX_N];
	int no[MAX_N];
	void init(){
		sz = 1;
		memset(ch[0],0,sizeof(ch[0]));
		val[0] = 0;
		no[0] = 0;
	}
	int idx(char c){
		return c - 'a';
	}
	void insert(char *s,int st,int ed,int v){
		int u = 0;
		//int n = strlen(s);
		for (int i=st;i<=ed;i++){
			int c = idx(s[i]);
			if (no[u]!=v)	// 这里是为了不重复计数,如果插入的点
				val[u]++;   // 是当前的串的子串,所有的该串子串都
							// 会有特定的v的标记,碰到了就避免计数
			if (!ch[u][c]){
				memset(ch[sz],0,sizeof(ch[sz]));
				val[sz] = 0;
				no[sz] = 0;
				ch[u][c] = sz++;
			}
			u = ch[u][c];
		}
		if (no[u]!=v)  // 不要忘了在插入的末尾,可能还会有相同的子串诺
			val[u]++;
		no[u] = v;
	}
	int query(char *s){
		int u = 0;
		int n = strlen(s);
		for (int i=0;i<n;i++){
			int c = idx(s[i]);
			if (!ch[u][c]){
				return 0;
			}
			u = ch[u][c];
		}
		return val[u];
	}
}trie;
void print(char *s,int st,int ed,int num){
	printf("%d \n\n",num);
	for (int i=st;i<=ed;i++){
		printf("%c",s[i]);
	}
	cout << endl;
}
int n,m;
bool vis[10009];
void input(){
	trie.init();
	char s[30];
	for (int i=1;i<=n;i++){
		scanf("%s",s);
		int len = strlen(s);
		for (int j=len-1;j>=0;j--){
			for (int k=j;k<len;k++){
				trie.insert(s,j,k,i);
				//print(s,j,k,i);
			}
		}
	}
	scanf("%d",&m);
	for (int i=1;i<=m;i++){
		scanf("%s",s);
		printf("%d\n",trie.query(s));
	}
	//memset(vis,0,sizeof(vis))
	
}
int main(){
	//freopen("1.txt","r",stdin);
	while(scanf("%d",&n)!=EOF){
		input();
	}
	return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文:http://blog.csdn.net/timelimite/article/details/47190769