首页 > 其他 > 详细

BZOJ.3277.串(广义后缀自动机)

时间:2018-06-28 22:37:23      阅读:183      评论:0      收藏:0      [点我收藏+]

题目链接

\(Description\)

给定n个串和K,求每个串中有多少个子串是这n个串中至少K个串的子串。

\(Solution\)

上题,我们可以算出每个节点所代表的串出现在了几个串中;而且我们知道,对于每个节点i,它代表的串的数量为len[i]-len[fa[i]]。
建立广义后缀自动机,预处理每个节点的cnt。每个节点的val可以根据cnt是否>=K设为len[i]-len[fa[i]]或0。
我们要求的是所有子串,所以如果统计val[i],也要算上val[fa[i]],val[fa[fa[i]]]...直接建出parent树从上到下DFS更新每个点。
对于每个要求答案的串,在SAM上走一遍并累加所有经过节点的更新后的val即可。
求答案的时候因为不能存串,so用个链表/vector存下所有经过点来。

我并不想看100+行的SA+二分。。

跑得略慢啊

//30740kb   612ms
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
#define gc() getchar()
typedef long long LL;
const int N=2e5+5;//∑len <= 1e5 ?

struct Suffix_Automaton
{
    int n,K,las,tot,fa[N],son[N][26],len[N],cnt[N],bef[N],Enum,H[N],nxt[N],to[N];//parent树空间是2n啊 
    LL val[N];
    char s[N>>1];
    std::vector<int> v[N>>1];

    void Init(int nn){
        n=nn, scanf("%d",&K), las=tot=1;
    }
    inline void AddEdge(int u,int v){
        to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum;
    }
    void Insert(int now,int c)
    {
        int p=las,np=++tot; len[las=np]=len[p]+1;
        for(; p&&!son[p][c]; p=fa[p]) son[p][c]=np;
        if(!p) fa[np]=1;
        else
        {
            int q=son[p][c];
            if(len[q]==len[p]+1) fa[np]=q;
            else
            {
                int nq=++tot;
                len[nq]=len[p]+1, bef[nq]=bef[q], cnt[nq]=cnt[q];
                memcpy(son[nq],son[q],sizeof son[q]);
                fa[nq]=fa[q], fa[q]=fa[np]=nq;
                for(; son[p][c]==q; p=fa[p]) son[p][c]=nq;
            }
        }
        v[now].push_back(np);
        for(; bef[np]!=now&&np; np=fa[np])
            ++cnt[np], bef[np]=now;
    }
    void Build(int now)
    {
        scanf("%s",s), las=1;//las=1! 
        for(int i=0,l=strlen(s); i<l; ++i)
            Insert(now,s[i]-'a');
    }
    void DFS(int x)
    {
        val[x]+=val[fa[x]];
        for(int i=H[x]; i; i=nxt[i]) DFS(to[i]);
    }
    void Solve()
    {
        for(int i=2; i<=tot; ++i)
        {
            AddEdge(fa[i],i);
            if(cnt[i]<K) val[i]=0;
            else val[i]=len[i]-len[fa[i]];
        }
        DFS(1);
        for(int i=1; i<=n; ++i)
        {
            LL res=0;
            for(int j=0,l=v[i].size(); j<l; ++j)
                res+=val[v[i][j]];
            printf("%lld ",res);
        }
    }
}sam;

int main()
{
    int n; scanf("%d",&n), sam.Init(n);
    for(int i=1; i<=n; ++i) sam.Build(i);
    sam.Solve();
    return 0;
}

BZOJ.3277.串(广义后缀自动机)

原文:https://www.cnblogs.com/SovietPower/p/9241115.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!