Bzoj3172 单词
Posted cutemush
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Bzoj3172 单词相关的知识,希望对你有一定的参考价值。
某人读论文,一篇论文是由许多单词组成。
但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次。
Input
第一个一个整数N,表示有多少个单词,接下来N行每行一个单词。
每个单词由小写字母组成,N<=200,单词长度不超过10^6
Output
输出N个整数,第i行的数字表示第i个单词在文章中出现了多少次。
Sample Input
3
a
aa
aaa
Sample Output
6
3
1
暴力算法:
以每个词为文本串做匹配,每匹配上一个位置,就从该节点延fail或last数组上溯,给经过的的词尾结点加上1次出现次数
优化:
由上述算法可知,每个文本串(即每个单词)在AC自动机上的每个结点,都可以使 其延fail数组能走到的单词 的出现次数加1
因此,可以建出fail树,给每个单词在AC自动机上的每个结点标号都加1(打标记),意味着其父结点中词尾的出现次数增加1
但这里不上溯,在fail树上做一次dp(类似前缀和)
这里可以直接利用建立AC自动机时的队列,从后往前,每个元素对应fail树中的结点层数一定是从高到低的
处理重复单词:
若单词i与j相同(i<j),就用链表把j接到i的后面,AC自动机的词尾结点上记录该词第一次出现的序号,即可
原文链接:https://blog.csdn.net/wangyh1008/article/details/81501988
#include<cstdio> #include<iostream> #include<cmath> #include<cstring> #include<algorithm> #include<cstdlib> using namespace std; const int N=1000005; int ch[N][30],val[N],lastnum[N],sum[N],q[N],tot=0,ans[N],f[N]; char st[N]; void insert(int t) { int u=0,n=strlen(st); for (int i=0; i<n; i++){ int c=st[i]-‘a‘; if (!ch[u][c]) ch[u][c]=++tot; u=ch[u][c]; sum[u]++; } if (val[u]==0) val[u]=lastnum[t]=t; else lastnum[t]=val[u]; } void pre() { int head=0,tail=0; for (int i=0; i<26; i++) if (ch[0][i]>0) q[tail++]=ch[0][i]; while (head<tail){ for (int i=0; i<26; i++) if(ch[q[head]][i]>0){ q[tail++]=ch[q[head]][i]; int u=f[q[head]]; while(u>0 && ch[u][i]==0) u=f[u]; f[ch[q[head]][i]]=ch[u][i]; } head++; } for (int i=tail-1; i>=0; i--){ if (val[q[i]]>0) ans[val[q[i]]]=sum[q[i]]; sum[f[q[i]]]+=sum[q[i]]; } } int main() { int n; scanf("%d",&n); for (int i=1; i<=n; i++) scanf("%s",st),insert(i); pre(); for (int i=1; i<=n; i++) printf("%d ",ans[lastnum[i]]); return 0; }
Trie图
#include<stdio.h> #include<string.h> int ch[200010][26],ans[200010],id[210],que[200010],fil[200010],tot; char s[100010]; void ins(int x) { scanf("%s",s+1);int n=strlen(s+1),p=0; for(int i=1;i<=n;i++) { if(!ch[p][s[i]-‘a‘])ch[p][s[i]-‘a‘]=++tot; p=ch[p][s[i]-‘a‘]; ans[p]++; } id[x]=p; } int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++)ins(i); int q1=1,q2=0; for(int i=0;i<26;i++)if(ch[0][i])que[++q2]=ch[0][i]; while(q1<=q2) {w int u=que[q1++]; for(int i=0;i<26;i++) if(ch[u][i]) fil[ch[u][i]]=ch[fil[u]][i],que[++q2]=ch[u][i]; else ch[u][i]=ch[fil[u]][i]; } for(int i=tot;i>=1;i--) ans[fil[que[i]]]+=ans[que[i]]; for(int i=1;i<=n;i++)printf("%d ",ans[id[i]]); return 0; }
以上是关于Bzoj3172 单词的主要内容,如果未能解决你的问题,请参考以下文章