CF452E Three strings 广义SAM

题意:

戳这里

分析:

一看多串匹配直接上广义 \(SAM\) ,每一个节点分别维护一下三个串的 \(siz\) 这样答案每一个点对答案的贡献就是 长度在 \(len[link[x]]\)\(len[x]\) 之间每一个长度的匹配数都会加上 \(siz[a]*siz[b]*siz[c]\)

不过这里学到了一个小技巧,正确的在线构造的广义 \(SAM\) (即有两个特判的 \(SAM\)) 是可以基数排序得到拓扑序的,这样就不用 \(DFS\)

代码:

#include<bits/stdc++.h>

using namespace std;

namespace zzc
{
    const int maxn = 6e5+5;
    const long long mod = 1e9+7;
    int n[3];
    char ch[300005];

    struct suffix_automaton
    {
        int lst,tot;
        int trans[maxn][26],len[maxn],link[maxn],sa[maxn],cnt[maxn];
        long long ans[maxn],siz[maxn][3];
        suffix_automaton(){tot=lst=1;}

        void insert(int x,int id)
        {
            int tmp=lst;
            if(trans[tmp][x])
            {
                int q=trans[tmp][x];
                if(len[tmp]+1==len[q]) lst=q;
                else
                {
                    int clone=++tot;
                    link[clone]=link[q];
                    link[q]=clone;
                    len[clone]=len[tmp]+1;
                    for(int i=0;i<26;i++) trans[clone][i]=trans[q][i];
                    for(;tmp&&trans[tmp][x]==q;tmp=link[tmp]) trans[tmp][x]=clone;
                    lst=clone;
                }
                siz[lst][id]++;
                return ;
            }
            int cur=++tot;lst=tot;siz[cur][id]++;
            len[cur]=len[tmp]+1;
            for(;tmp&&!trans[tmp][x];tmp=link[tmp]) trans[tmp][x]=cur;
            if(!tmp)
            {
                link[cur]=1;
            }
            else
            {
                int q=trans[tmp][x];
                if(len[q]==len[tmp]+1)
                {
                    link[cur]=q;
                }
                else
                {
                    int clone=++tot;
                    len[clone]=len[tmp]+1;
                    link[clone]=link[q];
                    link[q]=link[cur]=clone;
                    for(int i=0;i<26;i++) trans[clone][i]=trans[q][i];
                    for(;tmp&&trans[tmp][x]==q;tmp=link[tmp]) trans[tmp][x]=clone;
                }
            }
        }
    
        void sort()
        {
            for(int i=1;i<=tot;i++) cnt[len[i]]++;
            for(int i=1;i<=tot;i++) cnt[i]+=cnt[i-1];
            for(int i=1;i<=tot;i++) sa[cnt[len[i]]--]=i;
            for(int i=tot;i>=2;i--)
            {
                int now=sa[i];
                for(int j=0;j<3;j++) siz[link[now]][j]+=siz[now][j];
                long long res=siz[now][0]*siz[now][1]*siz[now][2]%mod;
                ans[len[link[now]]+1]=(ans[len[link[now]]+1]+res)%mod;
                ans[len[now]+1]=(ans[len[now]+1]-res+mod)%mod;
            }
            for(int i=1;i<=tot;i++) ans[i]=(ans[i]+ans[i-1])%mod;
            for(int i=1,j=min(n[0],min(n[1],n[2]));i<=j;i++) printf("%lld ",ans[i]);
        }

    }sam;
    
    void work()
    {
        for(int i=0;i<3;i++)
        {
            scanf("%s",ch+1);n[i]=strlen(ch+1);sam.lst=1;
            for(int j=1;j<=n[i];j++) sam.insert(ch[j]-'a',i);
        }
        sam.sort();
    }
}


int main()
{
    zzc::work();
    return 0;
}
posted @ 2021-01-02 11:04  youth518  阅读(78)  评论(0编辑  收藏  举报