BZOJ 3172: [Tjoi2013]单词
3172: [Tjoi2013]单词
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 3439 Solved: 1650
[Submit][Status][Discuss]
Description
某人读论文,一篇论文是由许多单词组成。但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次。
Input
第一个一个整数N,表示有多少个单词,接下来N行每行一个单词。每个单词由小写字母组成,N<=200,单词长度不超过10^6
Output
输出N个整数,第i行的数字表示第i个单词在文章中出现了多少次。
Sample Input
3
a
aa
aaa
a
aa
aaa
Sample Output
6
3
1
3
1
HINT
Source
分析:
我们对于每一个节点维护其子树fail指针和...就是答案...
代码:
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> //by NeighThorn using namespace std; const int maxn=200+5,maxm=1000000+5; int n,tot,head,tail,q[maxm],pos[maxn]; char s[maxm]; struct trie{ int sum,fail,nxt[26]; }tr[maxm]; inline void insert(int &x){ scanf("%s",s);int p=0,len=strlen(s); for(int i=0;i<len;i++){ if(!tr[p].nxt[s[i]-'a']) tr[p].nxt[s[i]-'a']=++tot,tr[tot].fail=-1; p=tr[p].nxt[s[i]-'a'],tr[p].sum++; } x=p; } inline void buildACM(void){ head=0,tail=0;q[0]=0; while(head<=tail){ int id=q[head++],p=-1; for(int i=0;i<26;i++) if(tr[id].nxt[i]){ if(id){ p=tr[id].fail; while(p!=-1){ if(tr[p].nxt[i]){ tr[tr[id].nxt[i]].fail=tr[p].nxt[i]; break; } p=tr[p].fail; } if(p==-1) tr[tr[id].nxt[i]].fail=0; } else tr[tr[id].nxt[i]].fail=0; q[++tail]=tr[id].nxt[i]; } } for(int i=tail;i>=0;i--) tr[tr[q[i]].fail].sum+=tr[q[i]].sum; } signed main(void){ scanf("%d",&n);tr[0].fail=-1; for(int i=1;i<=n;i++) insert(pos[i]); buildACM(); for(int i=1;i<=n;i++) printf("%d\n",tr[pos[i]].sum); return 0; }
By NeighThorn