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 单词的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 3172 单词

BZOJ 3172: [Tjoi2013]单词

BZOJ 3172 [Tjoi2013]单词

BZOJ3172: [Tjoi2013]单词

BZOJ3172单词(AC自动机)

Bzoj3172 单词