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
题解:在fail树上统计一下就好了。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 1000005
using namespace std;
int pos[N],n;
struct acm{
int cnt,fail[N],q[N],next[N][30],sum[N];
char ch[N];
acm(){cnt=1;for (int i=0;i<26;i++) next[0][i]=1;}
void insert(int &pos){
scanf("%s",ch);int now=1;int l=strlen(ch);
for (int i=0;i<l;i++){
if (!next[now][ch[i]-'a']) next[now][ch[i]-'a']=++cnt;
now=next[now][ch[i]-'a'];sum[now]++;
}
pos=now;
}
void buildfail(){
int h=0,t=1;q[0]=1;fail[1]=0;
while (h!=t){
int now=q[h++];
for (int i=0;i<26;i++){
int u=next[now][i];if (!u) continue;
int k=fail[now];
while (!next[k][i]) k=fail[k];
fail[u]=next[k][i];q[t++]=u;
}
}
for (int i=t-1;i>=0;i--) sum[fail[q[i]]]+=sum[q[i]];
}
}acm;
int main(){
scanf("%d",&n);
for (int i=1;i<=n;i++)acm.insert(pos[i]);
acm.buildfail();
for (int i=1;i<=n;i++) printf("%d\n",acm.sum[pos[i]]);
}