【BZOJ】【3172】【TJOI2013】单词
AC自动机
Orz zyf
玛雅一开始连题意都没看懂……意思就是给你一篇文章的N个单词,问每个单词在这篇文章中各出现了几次?(这篇文章=N个单词)
那么我们建个AC自动机……对于每个单词来说,它出现的次数=以它为根的fail树的大小,即询问有多少点沿fail指针能走到这个单词的结束结点。
但是我们有更简单的算法= =(orz zyf)
AC自动机的话我们直接其实就是查询有多少个节点通过fail能到达该串的结束节点,既然这样符合条件的一定bfs的时候在该点之后
那么我们按bfs逆序执行w[go[i]]+=w[i]即可。正确性显然。
1 /************************************************************** 2 Problem: 3172 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:4432 ms 7 Memory:119436 kb 8 ****************************************************************/ 9 10 //BZOJ 3172 11 #include<vector> 12 #include<cstdio> 13 #include<cstring> 14 #include<cstdlib> 15 #include<iostream> 16 #include<algorithm> 17 #define rep(i,n) for(int i=0;i<n;++i) 18 #define F(i,j,n) for(int i=j;i<=n;++i) 19 #define D(i,j,n) for(int i=j;i>=n;--i) 20 #define pb push_back 21 using namespace std; 22 inline int getint(){ 23 int v=0,sign=1; char ch=getchar(); 24 while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();} 25 while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();} 26 return v*sign; 27 } 28 const int N=1e6+10,INF=~0u>>2; 29 typedef long long LL; 30 /******************tamplate*********************/ 31 int n,cnt=1,pos[N]; 32 struct Trie{ 33 int ch[26],fail,w; 34 }T[N]; 35 char s[N]; 36 void ins(char *s,int num){ 37 int x=1,y; 38 rep(i,strlen(s)){ 39 y=s[i]-'a'; 40 if (!T[x].ch[y]) T[x].ch[y]=++cnt; 41 x=T[x].ch[y]; 42 T[x].w++; 43 } 44 pos[num]=x; 45 } 46 int Q[N],l=0,r=-1; 47 void make_fail(){ 48 Q[++r]=1; 49 while(l<=r){ 50 int x=Q[l++],y,j; 51 rep(i,26){ 52 j=T[x].fail; 53 while(j && !T[j].ch[i]) j=T[j].fail; 54 if (T[x].ch[i]){ 55 y=T[x].ch[i]; 56 T[y].fail=j ? T[j].ch[i] : 1; 57 Q[++r]=y; 58 }else T[x].ch[i]=j ? T[j].ch[i] : 1; 59 } 60 } 61 } 62 63 int main(){ 64 #ifndef ONLINE_JUDGE 65 freopen("3172.in","r",stdin); 66 freopen("3172.out","w",stdout); 67 #endif 68 n=getint(); cnt=1; 69 F(i,1,n){ 70 scanf("%s",s); 71 ins(s,i); 72 } 73 make_fail(); 74 D(i,r,0) T[T[Q[i]].fail].w+=T[Q[i]].w; 75 F(i,1,n) printf("%d\n",T[pos[i]].w); 76 return 0; 77 }
3172: [Tjoi2013]单词
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 1573 Solved: 723
[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