2020牛客多校 第四场 C Count New String(广义后缀自动机)

题意等价于对(S)(|S|)个后缀进行(f)操作,求这|S|个操作后的后缀的本质不同的子串个数


把每个操作后的后缀翻转后插入字典树
当所有后缀都插入字典树之后建广义后缀自动机
直接统计答案即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e6;
int fa[maxn],c[maxn],tr[maxn][10],tot=0;
int ins(char ch,int pos)
{
    int id=ch-'a';
    if(!tr[pos][id])
    {
        tr[pos][id]=++tot;
        fa[tot]=pos;
        c[tot]=id;
    }
    return tr[pos][id];
}
#define Cpy(a, b) memcpy(a, b, sizeof(a))
struct Suffix_Automata
{
    int maxlen[maxn], trans[maxn][10], link[maxn], Size,pos[maxn];
    Suffix_Automata() { Size = 1; }
    inline int Extend(int id,int Last)
    {
        int cur = (++Size), p;
        maxlen[cur] = maxlen[Last] + 1;
        for (p = Last; p && !trans[p][id]; p = link[p])
            trans[p][id] = cur;
        if (!p)
            link[cur] = 1;
        else 
        {
            int q = trans[p][id];
            if (maxlen[q] == maxlen[p] + 1) 
                link[cur] = q;
            else  
            {
                int clone = (++Size);
                maxlen[clone] = maxlen[p] + 1;
                Cpy(trans[clone], trans[q]);
                link[clone] = link[q];
                for (; p && trans[p][id] == q; p = link[p])
                    trans[p][id] = clone;
                link[cur] = link[q] = clone;
            }
        }
        return cur;
    }
    inline void build()
    {
        queue<int>q;
        for(int i=0;i<10;++i)
        {
            if(tr[0][i])
                q.push(tr[0][i]);
        }
        pos[0]=1;
        while(!q.empty())
        {
            int x=q.front();q.pop();
            pos[x]=Extend(c[x],pos[fa[x]]);
            for(int i=0;i<10;++i)
                if(tr[x][i])q.push(tr[x][i]);
        }
    }
    inline void cal(){
        ll ans=0;
        for(int i=2;i<=Size;++i)ans+=maxlen[i]-maxlen[link[i]];
        printf("%lld
",ans);
    }
} sam;
char s[maxn];
int pre[maxn];
int main()
{
    scanf("%s",s+1);
    int len=strlen(s+1);
    for (int i = len; i >= 1; i--)
    {
        int p = 0;
        for (int j = i + 1; j <= len; j++)
        {
            if (s[i] > s[j]) s[j] = s[i];
            else
            {
                p = j;
                break;
            }
        }
        int sta;
        if (p == 0) sta = len;
        else sta = p - 1;
        pre[i] = pre[p];
        for (int j = sta; j >= i; j--) pre[i] = ins(s[i], pre[i]);
    }
    sam.build();
    sam.cal();
    return 0;
}
原文地址:https://www.cnblogs.com/Zeronera/p/13365089.html