zoukankan      html  css  js  c++  java
  • P3975 (后缀自动机sort)

    题目链接:

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

    题意:

    求出所有字串的第k大子串

    有两种,第一种对于出现在不同位置的相同子串算作一个子串

    第二种,对于不同位置的子串算作是不相同子串

    数据范围:

    $1leq |S| leq5000 00$

    分析: 

    对于第一种计算,endpos算作1,对于第二种,endpos是状态出现的次数

    对于当前状态前缀出现的次数为endpos+子状态的出现次数

    sam的拓扑序可以根据maxlen来排,maxlen越大,拓扑序肯定越小,无论是slink,还是trans边,都是短的maxlen链接长的maxlen

    用桶排序实现$O(n)$为它们排序

    AC代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e6+10;
    typedef long long ll;
    char S[N/2];
    char ans[N/2];
    int fla,k,top;
    struct suffixautomation
    {
        int mp[N][30];int fa[N];int ed;int ct;int len[N];int siz[N];
        ll weight[N];
        int z[N],A[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(){
            //sort
            for(int i=1;i<=ct;i++)z[len[i]]++;
            for(int i=1;i<=ct;i++)z[i]+=z[i-1];
            for(int i=1;i<=ct;i++)A[z[len[i]]--]=i;
    
            for(int i=ct;i>=1;i--){
                if(fla)siz[fa[A[i]]]+=siz[A[i]];
                else siz[fa[A[i]]]=1;
            }
            for(int i=ct;i>=1;i--){
             //   cout<<A[i]<<endl;
                int v=A[i];
                weight[v]=siz[v];
                for(int j=1;j<=26;j++)
                    if(mp[v][j])weight[v]+=weight[mp[v][j]];
            }
            weight[1]-=siz[1];
            if(k>weight[1]){
                printf("-1
    ");
                return ;
            }
            int now=1;
            while(1){
                for(int i=1;i<=26;i++)
                    if(k>weight[mp[now][i]]){
                        k-=weight[mp[now][i]];
                    }else{
                        now=mp[now][i];
                        ans[++top]='a'+i-1;
                        break;
                    }
                if(k<=siz[now])break;
                else k-=siz[now];
            }
            ans[++top]=0;
            printf("%s
    ",ans+1);
        }
    }sam;
    int main()
    {
        scanf("%s",S+1);
        scanf("%d %d",&fla,&k);
        int len=strlen(S+1);
        for(int i=1;i<=len;i++)sam.ins(S[i]-'a'+1,i);
        sam.solve();
        return 0;
    }
    

      

  • 相关阅读:
    MSsql bcp
    mssql 动态行转列。
    Ms sql 2000互转2005
    Ms sql pivot unpivot
    Ms sql将首字母大写
    java 进制相互转换
    Java 对字符反转操作。
    java jdbc 封装。。
    java SimpleDateFormat
    《more effective C++》条款10 防止构造函数里的资源泄露
  • 原文地址:https://www.cnblogs.com/carcar/p/11635985.html
Copyright © 2011-2022 走看看