• 弦论(tjoi2015,bzoj3998)(sam(后缀自动机))


    对于一个给定长度为(N)的字符串,求它的第(K)小子串是什么。

    Input

    第一行是一个仅由小写英文字母构成的字符串(S)

    第二行为两个整数(T)(K)(T)为0则表示不同位置的相同子串算作一个。(T=1)则表示不同位置的相同子串算作多个。(K)的意义如题所述。

    Output

    输出仅一行,为一个数字串,为第(K)小的子串。如果子串数目不足(K)个,则输出(-1)

    Sample Input

    aabc
    0 3
    

    Sample Output

    aab
    

    Hint

    (N<=5*10^5)

    (T<2)

    (K<=1e9)

    题意:

    中文题面,不解释。

    题解:

    把串放进后缀自动机,然后处理一遍,如果(T=0),则所有点权为1;否则,把每个点的(parent)加上当前(size)。然后反向拓扑,像求第(k)大子串如这个一样求就行了。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1000010;
    char s[N];
    int a[N],c[N];
    void cmax(int &a,int b){
        a=max(a,b);
    }
    void cmin(int &a,int b){
        a=min(a,b);
    }
    struct SAM{
        int last,cnt;
        int size[N],ch[N][26],fa[N<<1],l[N<<1],sum[N];
        void ins(int c){
            int p=last,np=++cnt;last=np;l[np]=l[p]+1;
            for(;p&&!ch[p][c];p=fa[p])ch[p][c]=np;
            if(!p)fa[np]=1;
            else{
                int q=ch[p][c];
                if(l[p]+1==l[q])fa[np]=q;
                else{
                    int nq=++cnt;l[nq]=l[p]+1;
                    memcpy(ch[nq],ch[q],sizeof ch[q]);
                    fa[nq]=fa[q];fa[q]=fa[np]=nq;
                    for(;ch[p][c]==q;p=fa[p])ch[p][c]=nq;
                }
            }
            size[np]=1;
        }
        void build(char s[]){
            int len=strlen(s+1);
            last=cnt=1;
            for(int i=1;i<=len;++i)ins(s[i]-'a');
        }
        void calc(int op){
        	memset(c,0,sizeof c);
            for(int i=1;i<=cnt;++i)c[l[i]]++;
            for(int i=1;i<=cnt;++i)c[i]+=c[i-1];
            for(int i=1;i<=cnt;++i)a[c[l[i]]--]=i;
            for(int i=cnt;i;--i){
                int p=a[i],f=fa[p];
                if(op){
                    size[f]+=size[p];
                }else{
                    size[p]=1;
                }
            }
            size[1]=0;
            for(int i=cnt;i;--i){
                int p=a[i];
                sum[p]=size[p];
                for(int j=0;j<26;++j){
                    if(ch[p][j])sum[p]+=sum[ch[p][j]];
                }
            }
        }
        void find(int k){
            int p=1;
            size[0]=0;
            while(k){
                int a=0;
                while(k>sum[ch[p][a]]&&a<26){
                    if (ch[p][a]) k-=sum[ch[p][a]];
                    a++;
                }
                if(a>=26){
                    puts("-1");
                    return;
                }
                putchar('a'+a);k-=size[ch[p][a]];
                if(k<=0)return;
                p=ch[p][a];
            }
        }
    }sam;
    int main(){
        cin>>s+1;
        sam.build(s);
        int t,k;
        cin>>t>>k;
        sam.calc(t);
        sam.find(k);
    }
    
  • 相关阅读:
    delphi安装pngimage控件,不需要安装,只需引用就行
    怎样把PL/SQLDeveloper字体调大
    resource is out of sync with the file
    SecureCRT:[1]SecureCRT配色方案
    安装开发环境注意事项2
    插入排序
    tomcat更改端口序
    tomcat更改端口
    maven添加jar包
    java总结
  • 原文地址:https://www.cnblogs.com/zhenglier/p/10098710.html
Copyright © 2020-2023  润新知