BZOJ3172: [Tjoi2013]单词
Posted Star_Feel
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ3172: [Tjoi2013]单词相关的知识,希望对你有一定的参考价值。
【传送门:BZOJ3172】
简要题意:
给出n个单词,你可以理解为将这些单词变成一个个段落,然后求出每个单词在所有段落中出现的次数
题解:
刚开始不是很懂题目,结果发现将所有单词看成一篇文章,每个单词看成一个段落就懂了
由于某种unbelievable的原因,我刚好做了AC自动机的专题训练,看到这道题就秒想AC自动机
将每个单词放进AC自动机里,每个点的s表示有多少个单词经过,然后在构建失败指针的时候,通过队列来更新s值,怎么更新呢,假设有一个i点,它的失败指针指向j,设sj为从根到j点所构成的字符串,si为从根到i点所构成的字符串,那么我们可以知道sj为si的后缀,也说明了si中有sj的出现,那么就将j点的s值加上i点的s值,达到更新且不重复的目的来求出答案
参考代码:
#include<queue> #include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<cmath> using namespace std; struct node { int s,c[27],fail; node() { s=fail=0; memset(c,-1,sizeof(c)); } }t[1100000]; int tot,ans,n; char a[1100000]; int ed[210]; void bt(int k,int root) { int x=root,len=strlen(a+1); for(int i=1;i<=len;i++) { int y=a[i]-‘a‘+1; if(t[x].c[y]==-1) { t[x].c[y]=++tot; } x=t[x].c[y]; t[x].s++; } ed[k]=x; } int list[1100000]; void bfs() { int x; int head=1,tail=1; list[1]=0; while(head<=tail) { x=list[head]; for(int i=1;i<=26;i++) { int son=t[x].c[i]; if(son==-1)continue; if(x==0) t[son].fail=0; else { int j=t[x].fail; while(j!=0&&t[j].c[i]==-1) j=t[j].fail; t[son].fail=max(t[j].c[i],0); int x=t[son].fail,y=son; } list[++tail]=son; } head++; } for(int i=tail;i>=1;i--) t[t[list[i]].fail].s+=t[list[i]].s; } int main() { ans=tot=0; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%s",a+1); bt(i,0); } bfs(); for(int i=1;i<=n;i++) { printf("%d\n",t[ed[i]].s); } return 0; }
以上是关于BZOJ3172: [Tjoi2013]单词的主要内容,如果未能解决你的问题,请参考以下文章