ac自动机
问题 D: 单词(word)
时间限制: 1 Sec 内存限制: 512 MB题目描述
某人读论文,一篇论文是由许多单词组成。但他发现一个单词会在论文中出现很多 次,现在想知道每个单词分别在论文中出现多少次。
输入
第一行一个整数 N, 表示有多少个单词,接下来 N 行每行一个单词。每个单词由小 写字母组成。
输出
输出 N 行,每行一个整数,第 i 行的数字表示第 i 个单词在文章中出现了多少次。
样例输入
3
a
aa
aaa
样例输出
6
3
1
提示
对于 100% 数据,N<=200, 单词总长度不超过 10^6。 对于 20% 数据,每个单词长度不超过 3。 对于 30% 数据,每个单词长度不超过 4.。 对于另 10% 数据,所有字符相同。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
template<typename T>
inline void read(T &a){
a=0;bool b=0;char x=getchar();
while(x<'0'||'9'<x){
if(x=='-')b=1;
x=getchar();
}
while('0'<=x&&x<='9'){
a=(a<<1)+(a<<3)+x-'0';
x=getchar();
}
if(b)a=-a;
}
char C_[50];
int TEMP;
template<typename T>
inline void write(T a){
if(a<0){
a=-a;
putchar('-');
}
do{
C_[++TEMP]=a%10+'0';
a/=10;
}while(a);
while(TEMP)putchar(C_[TEMP--]);
}
int n;
char ch[205];
int to[1000005][27],cnt,size[1000005];
inline void insert(){
int u=0,len=strlen(ch+1);
for(int i=1;i<=len;i++){
int v=ch[i]-'a';
if(!to[u][v])to[u][v]=++cnt;
u=to[u][v];
}
size[u]++;
//printf("%d %d\n",u,size[u]);
}
int fail[1000005],queue[1000005],rear,front;
inline void ac_auto(){
rear=front=0;
for(int i=0;i<26;i++)if(to[0][i])queue[rear++]=to[0][i];
while(front<rear){
int u=queue[front++];
for(int i=0;i<26;i++){
int v=to[u][i];
if(v)queue[rear++]=v;
int p=fail[u];
while(!to[p][i] && p)p=fail[p];
if(to[p][i])fail[v]=to[p][i];
}
}
}
bool vis[1000005];
inline int ac_query(){
int u=0,ans=0;
int len=strlen(ch+1);
for(int i=1;i<=len;i++){
int v=ch[i]-'a';
while(!to[u][v] && u)u=fail[u];
if(to[u][v])u=to[u][v];
for(int j=u;!vis[j];j=fail[j]){
ans+=size[j];
vis[j]=1;
}
}
printf("%d",ans);
}
int main(){
read(n);
for(int i=1;i<=n;i++){
scanf("%s",ch+1);
insert();
}
ac_auto();
scanf("%s",ch+1);
ac_query();
return 0;
}