zoukankan      html  css  js  c++  java
  • P3804 【模板】后缀自动机

    题目链接:

    https://www.luogu.org/problem/P3804

    题意:

    给出一个字符串,求出所有出现次数不为1的子串,长度×出现次数的最大值

    数据范围:

    $1leq |S| leq 1000 000$

    分析: 

    用SAM求出所有子串出现的次数即可

    洛谷模板:

    #include<bits/stdc++.h>
    using namespace std;const int N=2*1e6+10;typedef long long ll;
    char S[N];
    struct suffixautomation
    {
        int mp[N][30];int fa[N];int ed;int ct;int len[N];int siz[N];int deg[N];
        suffixautomation(){ed=ct=1;}
        inline void ins(int c,int pos)
        {
            int p=ed;siz[ed=++ct]=1;len[ed]=pos;//先初始化size和len
            for(;p&&mp[p][c]==0;p=fa[p]){mp[p][c]=ed;}//然后顺着parent树的路径向上找
            if(p==0){fa[ed]=1;return;}int q=mp[p][c];//case1
            if(len[p]+1==len[q]){fa[ed]=q;return;}//case2
            len[++ct]=len[p]+1;//case 3
            for(int i=1;i<=26;i++){mp[ct][i]=mp[q][i];}
            fa[ct]=fa[q];fa[q]=ct;fa[ed]=ct;
            for(int i=p;mp[i][c]==q;i=fa[i]){mp[i][c]=ct;}
        }
        void solve(){
            queue<int>que;
            for(int i=2;i<=ct;i++)deg[fa[i]]++;
            for(int i=1;i<=ct;i++)if(deg[i]==0)que.push(i);
            while(que.size()){
                int x=que.front();
                que.pop();
                if(x==1)break;
                int y=fa[x];
                siz[y]+=siz[x];
                deg[y]--;
                if(deg[y]==0)que.push(y);
            }
            ll ans=0;
            for(int i=1;i<=ct;i++)if(siz[i]>1)ans=max(ans,(ll)len[i]*siz[i]);
            printf("%lld
    ",ans);
        }
    }sam;
    int main()
    {
        scanf("%s",S+1);//没啥好说的,建sam然后dfs
        int len=strlen(S+1);
        for(int i=1;i<=len;i++)sam.ins(S[i]-'a'+1,i);
        sam.solve();
        return 0;//拜拜程序~
    }
    

      

      

    hiho模板:

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int MAXL = 1000000;
    string s;
    int n = 0,len,st;
    int maxlen[2 * MAXL + 10], minlen[2 * MAXL + 10], trans[2 * MAXL + 10][26], slink[2 * MAXL + 10];
    int endps[2 * MAXL +10],deg[2* MAXL+10];
    int new_state(int _maxlen, int _minlen, int* _trans, int _slink) {
            maxlen[n] = _maxlen;
            minlen[n] = _minlen;
            for(int i = 0; i < 26; i++) {
                    if(_trans == NULL)
                            trans[n][i] = -1;
                    else
                            trans[n][i] = _trans[i];
            }
            slink[n] = _slink;
            return n++;
    }
    
    int add_char(char ch, int u) {
            int c = ch - 'a';
            int z = new_state(maxlen[u] + 1, -1, NULL, -1);
            int v = u;
            while(v != -1 && trans[v][c] == -1) {
                    trans[v][c] = z;
                    v = slink[v];
            }
            if(v == -1) { //最简单的情况,suffix-path(u->S)上都没有对应字符ch的转移
                    minlen[z] = 1;
                    slink[z] = 0;
                    return z;
            }
            int x = trans[v][c];
            if(maxlen[v] + 1 == maxlen[x]) { //较简单的情况,不用拆分x
                    minlen[z] = maxlen[x] + 1;
                    slink[z] = x;
                    return z;
            }
            int y = new_state(maxlen[v] + 1, -1, trans[x], slink[x]); //最复杂的情况,拆分x
            slink[y] = slink[x];
            minlen[x] = maxlen[y] + 1;
            slink[x] = y;
            minlen[z] = maxlen[y] + 1;
            slink[z] = y;
            int w = v;
            while(w != -1 && trans[w][c] == x) {
                    trans[w][c] = y;
                    w = slink[w];
            }
            minlen[y] = maxlen[slink[y]] + 1;
            return z;
    }
    int main(){
        int u=new_state(0,0,NULL,-1);
        cin>>s;
        len=s.size();
        for(int i=0;i<len;i++){
            u=add_char(s[i],u);
            endps[u]=1;
        }
        ll ans=0;
        for(int i=1;i<n;i++){
            deg[slink[i]]++;
        }
        queue<int>que;
        for(int i=1;i<n;i++)
            if(deg[i]==0)que.push(i);
        while(que.size()){
            int x=que.front();
            que.pop();
            if(x==0)break;
            endps[slink[x]]+=endps[x];
            deg[slink[x]]--;
            if(deg[slink[x]]==0)que.push(slink[x]);
        }
        for(int i=1;i<n;i++)
            if(endps[i]!=1)ans=max(ans,(ll)endps[i]*maxlen[i]);
        printf("%lld
    ",ans);
        return 0;
    }
      
    

      

  • 相关阅读:
    教你写能被舒服舒服又舒服地调用的iOS库
    无比迅速敏捷地开发iOS超精美控件
    iOS中UIlabel多行文本展示使用小结
    诸葛亮诫子书
    保留开阔的心灵空间
    iOS长按手势列表拖拽功能实现
    iOS通知使用小结
    真正的成熟
    生活的常态
    记一次LNMP 502问题的解决 (Nginx 、php、php-fpm)
  • 原文地址:https://www.cnblogs.com/carcar/p/11631160.html
Copyright © 2011-2022 走看看