• 【字符串】后缀自动机SAM


    后缀自动机 SAM

    模板

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn=1e6+50;
    
    struct Node{
        int ch[26];
        int len,fa;
    }node[maxn<<1];
    int las=1,tot=1;
    /*
    结点node[]表示一个类
    las是未加入此字符前的最长前缀(==整个串)所属的结点编号
    tot是当前结点的总数
    */
    int siz[maxn<<1];
    ll num;//num 存不同子串的数量
    ll alllen;//所有不同子串的总长度
    void add(int c)
    {
        int p=las;int np=las=++tot;siz[tot]=1;
        node[np].len=node[p].len+1;
        for(;p&&!node[p].ch[c];p=node[p].fa)node[p].ch[c]=np;
        //p=fa(p) 即从长到短遍历旧串的所有后缀
        //node[p].ch[c]==0 如果旧串后缀添加新的字符c不是旧串字串 则 往新串的最长后缀所属结点连一条c边
        if(!p)node[np].fa=1;//字符c在旧串没有出现过 所以新类的父类只能是1
        else
        {
            int q=node[p].ch[c];
            if(node[q].len==node[p].len+1)node[np].fa=q;//q是找到的第一个与np不同而又有后缀关系的结点
            else//node[q].len>node[p].len+1
            {
                int nq=++tot;
                node[nq]=node[q];//strcpy(node[nq].ch,node[q].ch);ndoe[nq].fa=node[q].fa;
                node[nq].len=node[p].len+1;
                node[q].fa=node[np].fa=nq;
                for(;p&&node[p].ch[c]==q;p=node[p].fa)node[p].ch[c]=nq;
            }
        }
        num+=node[np].len-node[node[np].fa].len;
        alllen+=1ll*node[np].len*(node[np].len+1)/2-1ll*(node[node[np].fa].len)*(node[node[np].fa].len+1)/2;
    }
    char s[maxn];int len;
    
    //求出现次数最多的子串的次数********************************************
    //begin1
    int mx;//mx是子串出现次数的最大次数
    vector<int>p[maxn<<1];
    void dfsinit(){
        for(int i=2;i<=tot;i++)
            p[node[i].fa].push_back(i);
    }
    void dfs(int u)
    {
        for(int i=0;i<p[u].size();i++)
        {
            dfs(p[u][i]);
            siz[u]+=siz[p[u][i]];
        }
        if(siz[u]!=1)mx=max(mx,siz[u]);
    }
    void solve()
    {
        dfsinit();
        dfs(1);
        printf("%d
    ",mx);
    }
    //end1
    
    //输出第k小字符串*********************************************************
    //begin2
    /*
     * 对于以下两种情况,在跑dfs2之前 让siz[1]=0 (siz[root]=0)
     * 若是求可重复的第k小的字符串,则在dfs2()的函数里,让siz[u]=1,不用跑dfs
     * 若是求本质不同第k小的字符串, 则先跑上边的dfsinit()和dfs() ,然后用下边的dfs2
     */
    int siz2[maxn];bool vis[maxn];
    void dfs2(int u)
    {
        siz2[u]=siz[u];vis[u]=true;
        for(int i=0;i<26;i++)
            if(node[u].ch[i])
            {
                if(!vis[node[u].ch[i]])dfs2(node[u].ch[i]);
                siz2[u]+=siz2[node[u].ch[i]];
            }
    }
    void getch(int u,int num)
    {
        num-=siz[u];
        if(num<=0)return;
        for(int i=0;i<26;i++)
        {
            if(num<=siz2[node[u].ch[i]])
            {
                putchar(i+'a');
                getch(node[u].ch[i],num);
                return;
            }
            num-=siz2[node[u].ch[i]];
        }
    }
    //end2
    
    
    //求本质不同第k小字符串 的bfs做法***********************************************
    //begin3
    int bb[maxn],id[maxn],sz[maxn];
    void bfs(){
        for(int i=1;i<=tot;i++)bb[node[i].len]++;
        for(int i=1;i<=tot;i++)bb[i]+=bb[i-1];
        for(int i=1;i<=tot;i++)id[bb[node[i].len]--]=i;
        for(int i=tot;i>=1;i--){
            sz[id[i]]=1;
            for(int j=0;j<26;j++)
                if(node[id[i]].ch[j])sz[id[i]]+=sz[node[id[i]].ch[j]];
        }
    }
    void query(int k)
    {
        int u=1;
        while(k)
        {
            for(int i=0;i<26;i++)
            {
                if(!node[u].ch[i])continue;
                if(k>sz[node[u].ch[i]])k-=sz[node[u].ch[i]];
                else{
                    putchar('a'+i);
                    u=node[u].ch[i];
                    k--;break;
                }
            }
        }
        puts("");
    }
    //end3
    
    
    
    int main()
    {
        scanf("%s",s);len=strlen(s);
        for(int i=0;i<len;i++)add(s[i]-'a');
        int op,k;
        scanf("%d%d",&op,&k);
        //求第k小字符串
        if(op){
            dfsinit();
            dfs(1);
        }
        else{
            for(int i=2;i<=tot;i++)siz[i]=1;
        }
        siz[1]=0;
        dfs2(1);
        if(k>siz2[1]){
            puts("-1");return 0;
        }
        getch(1,k);
    }
    
  • 相关阅读:
    godaddy 问题
    2014.10.5 再次学习LINUX
    自测 基础 js 脚本。
    error: cast from ‘char*’ to ‘int’ loses precision
    python 使用 Pyscript 调试 报错
    VS2012出现加载失败时的解决办法 win7同样适用
    Program received signal SIGILL, Illegal instruction
    visual assist x 注释配置
    python 学习网站
    python 典型文件结构
  • 原文地址:https://www.cnblogs.com/kkkek/p/13796599.html
Copyright © 2020-2023  润新知