您的位置:首页 > 其它

[BZOJ3172][TJOI2013]单词(AC自动机)

2016-04-04 17:25 435 查看

题目描述

传送门

题解

记录每一个点建自动机时候的访问次数。

建Fail树,然后节点子树的大小即为当前点出现的次数。

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;

const int max_n=2e2+5;
const int max_s=1e6+5;

int n,pos[max_n];
int tot,ans[max_s],query[max_s],cnt;
char s[max_s];
int ch[max_s][30],fail[max_s];
queue <int> q;

inline void insert(int &loc){
int now=0,len=strlen(s);
for (int i=0;i<len;++i){
int x=s[i]-'a';
if (!ch[now][x])
ch[now][x]=++tot;
now=ch[now][x];
++ans[now];
}
loc=now;
}
inline void make_fail(){
while (!q.empty()) q.pop();

for (int i=0;i<26;++i)
if (ch[0][i])
q.push(ch[0][i]);
while (!q.empty()){
int now=q.front(); q.pop();
query[++cnt]=now;
for (int i=0;i<26;++i){
if (!ch[now][i]){
ch[now][i]=ch[fail[now]][i];
continue;
}
fail[ch[now][i]]=ch[fail[now]][i];
q.push(ch[now][i]);
}
}
}
inline void calc_ans(){
for (int i=cnt;i>=1;--i)
ans[fail[query[i]]]+=ans[query[i]];
}

int main(){
scanf("%d\n",&n);
for (int i=1;i<=n;++i){
gets(s);
insert(pos[i]);
}
make_fail();
calc_ans();
for (int i=1;i<=n;++i)
printf("%d\n",ans[pos[i]]);
}


总结

Fail神奇的特性:所有以x节点代表的字符串结尾的字符串节点,都在x的子树中。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: