3172: [Tjoi2013]单词
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 4110 Solved: 1990
[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
后缀自动机先挖个坑,马上就写
AC自动机的做法就非常好了
完美的线性复杂度
直接建AC自动机
每个单词构建过程中都把每个节点权值++
最后按fail树构建过程倒叙把权值加到fail里就行了
#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<string>
#include<bitset>
#include<queue>
#include<map>
#include<set>
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
void print(int x)
{if(x<0)putchar('-'),x=-x;if(x>=10)print(x/10);putchar(x%10+'0');}
const int N=1000100;
int trie[N][26],fail[N],danger[N],sz=1,pos[210];
void insert(char *s,int x)
{
register int i,k,now=1,len=strlen(s);
for(i=0;i<len;++i)
{
k=s[i]-'a';
if(!trie[now][k])trie[now][k]=++sz;
now=trie[now][k];danger[now]++;
}
pos[x]=now;
}
int q[N];
void build()
{
register int i,u,v,head=0,tail=1;
fail[1]=0;q[head]=1;
while(head<tail)
{
u=q[head++];
for(i=0;i<26;++i)
{
if(trie[u][i])
{
v=trie[u][i];
fail[v]=trie[fail[u]][i];
q[tail++]=v;
}
else trie[u][i]=trie[fail[u]][i];
}
}
}
char s[N];
int main()
{
int n=read();
register int i;
for(i=0;i<26;++i)trie[0][i]=1;
for(i=1;i<=n;++i){scanf("%s",s);insert(s,i);}
build();
for(i=sz;i;i--)danger[fail[q[i]]]+=danger[q[i]];
for(i=1;i<=n;++i){print(danger[pos[i]]);puts("");}
}
/*
3
a
aa
aaa
6
3
1
*/