Description
某人读论文,一篇论文是由许多单词组成。但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次。
N<=200,单词长度不超过10^6
Solution
题都读不懂,难度上升一个档,差评
真实的题意是把给出的n个单词连起来作为文章,中间用分隔符分#或者♂什么的隔开来,查询每个单词出现的次数
ac自动机裸题,建出fail后跑一遍查询为前缀的情况,再把贡献统计到fail上查询为后缀的情况
Code
#include <stdio.h>
#include <string.h>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define drp(i,st,ed) for (int i=st;i>=ed;--i)
const int N=2000005;
int rec[N][26],fail[N],count[N],cnt=0;
int pos[N];
int queue[N],head,tail;
char str[N];
int insert(char *str) {
int len=strlen(str);
int now=0;
rep(i,0,len-1) {
if (!rec[now][str[i]-'a']) {
rec[now][str[i]-'a']=++cnt;
}
now=rec[now][str[i]-'a'];
count[now]++;
}
return now;
}
void get_fail() {
head=1; tail=0;
rep(i,0,25) {
if (rec[0][i]) {
queue[++tail]=rec[0][i];
}
}
while (head<=tail) {
int now=queue[head++];
rep(i,0,25) {
if (rec[now][i]) {
int tmp=fail[now];
while (tmp&&!rec[tmp][i]) {
tmp=fail[tmp];
}
fail[rec[now][i]]=rec[tmp][i];
queue[++tail]=rec[now][i];
}
}
}
}
void solve(int n) {
drp(i,tail,1) {
count[fail[queue[i]]]+=count[queue[i]];
}
rep(i,1,n) printf("%d\n", count[pos[i]]);
}
int main(void) {
int n; scanf("%d",&n);
rep(i,1,n) {
scanf("%s",str);
pos[i]=insert(str);
}
get_fail();
solve(n);
return 0;
}