题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=3065
题目里面要我们计算每种单词出现的次数,重叠的也要计算,那么我们在查找的时候不要把标记单词结尾的数组(我这里是val)清零就可以重复计算每个单词出现的数量了。
代码:
#include<iostream> #include<cstring> #include<algorithm> #include<queue> #include<map> #include<stack> #include<cmath> #include<vector> #include<set> #include<cstdio> #include<string> #include<deque> using namespace std; typedef long long LL; #define eps 1e-8 #define INF 0x3f3f3f3f #define maxn 50005 int trie[maxn][95],fail[maxn],val[maxn],ID[maxn],num[maxn]; int n,m,k,t,cnt; char s[1005][55],str[2000005]; void init(){ memset(trie,0,sizeof(trie)); memset(fail,0,sizeof(fail)); memset(val,0,sizeof(val)); memset(num,0,sizeof(num)); cnt=0; } void insert(char *s,int id){ int root=0; for(int i=0;s[i];i++){ int x=s[i]-32; if(trie[root][x]==0) trie[root][x]=++cnt; root=trie[root][x]; } val[root]++; ID[root]=id;//记录编号 } void build_fail(){//构建fail指针 queue<int>q; int root=0; for(int i=0;i<95;i++){ if(trie[root][i]) q.push(trie[root][i]); } while(!q.empty()){ int u=q.front(); q.pop(); for(int i=0;i<95;i++){ if(trie[u][i]){//u存在儿子i,把i的fail指向fail[u]的儿子i fail[trie[u][i]]=trie[fail[u]][i]; q.push(trie[u][i]); }else{//不存在儿子i trie[u][i]=trie[fail[u]][i];//让fail[u]的儿子i成为u的儿子 } } } } void query(){ int len=strlen(str); int u=0; for(int i=0;i<len;i++){ int id=str[i]-32; u=trie[u][id]; int temp=u; while(temp){ if(val[temp]){//找到一个以id+32这个字符结束的单词,我们在这里不把它的标记数组val清零 num[ID[temp]]++; } temp=fail[temp]; } } } int main() { while(scanf("%d",&n)!=EOF){ init(); for(int i=1;i<=n;i++){ scanf("%s",s[i]); insert(s[i],i); } build_fail(); scanf("%s",str); query(); for(int i=1;i<=n;i++){ if(num[i]){ printf("%s: ",s[i]); printf("%d ",num[i]); } } } return 0; }