后缀自动机

两盒软妹~` 提交于 2020-02-08 02:30:58
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e6+9;//一般有2n个等价类
int tot=1,las=1;
char s[maxn];
long long ans=0;

struct NODE
{
    int ch[26];
    int len,fa;
    NODE()
    {
        memset(ch,0,sizeof(ch));
        len=fa=0;
    }
} dian[maxn];


void add(int c)//构造自动机
{
    int p=las,np=las=++tot;
    dian[np].len=dian[p].len+1;
    for(; p&&!dian[p].ch[c]; p=dian[p].fa)
        dian[p].ch[c]=np;
    if(!p)dian[np].fa=1;
    else
    {
        int q=dian[p].ch[c];
        if(dian[q].len==dian[p].len+1)
            dian[np].fa=q;
        else
        {
            int nq=++tot;
            dian[nq]=dian[q];
            dian[nq].len=dian[p].len+1;
            dian[q].fa=dian[np].fa=nq;
            for(; p&&dian[p].ch[c]==q; p=dian[p].fa)
                dian[p].ch[c]=nq;
        }
    }
}
long long coun_dif_num()
{
    long long ans = 0;
    for(int i= 1; i<=tot; i++)
    {
        ans +=dian[i].len-(dian[dian[i].fa].len+1)+1;
        //ans += max(i)-min(i)+1;每个等价类中的字符串数量

    }
    printf("%lld\n",ans);
    return ans;

}

void find_min_s(int n)//求串的最小表示,原串创建自动机时要加长一倍
{
    int now,i,j;
    now = 1;
    char ans[maxn];
    for(i = 0; i <n; i++)
    {
        for(j = 0; j<26; j++)
        {
            if(dian[now].ch[j]!=0)
            {
                now = dian[now].ch[j];
                ans[i] = j+'a';
                break;
            }
        }
    }
    ans[n] = 0;
}

int max_commom(char s2[])//计算s和自动机字符串的最长公共子串
{
    int ans = 0,len = 0;
    int now = 1;
    for(int i = 0;i<strlen(s2);i++)
    {
        int x = s2[i]-'a';
        if(dian[now].ch[x]>0)
        {
            len++;
            now = dian[now].ch[x];
        }
        else
        {
            while(now&&dian[now].ch[x]==0)
                now = dian[now].fa;
            if(!now)
            {
                len = 0;
                now = 1;
            }
            else
            {
                len = dian[now].len+1;
                now = dian[now].ch[x];
            }
        }
        ans = max(ans,len);
    }
    return ans;
}

int main()
{
    int cd;
    scanf("%s",s);
    cd=strlen(s);
    for(int i=0; i<cd; i++)
    {
        add(s[i]-'a');
    }
    coun_dif_num();

    for(int i=0; i<cd; i++)
    {
        add(s[i]-'a');
    }
   find_min_s(cd);



    return 0;
}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!