zoukankan      html  css  js  c++  java
  • bzoj 3998: [TJOI2015]弦论

    Description

    对于一个给定长度为N的字符串,求它的第K小子串是什么。
    Input
    第一行是一个仅由小写英文字母构成的字符串S
    第二行为两个整数T和K,T为0则表示不同位置的相同子串算作一个。T=1则表示不同位置的相同子串算作多个。K的意义如题所述。
    Output
    输出仅一行,为一个数字串,为第K小的子串。如果子串数目不足K个,则输出-1

    solution

    SPOJ7258 比较类似,只不过多了一个不同位置算多次,用到 SPOJNSUBSTR 的方法,因为父亲节点是当前节点的最大子集,所以在父亲节点出现过的,在当前节点一定出现过,所以直接将 (size) 累加到父亲节点上即可.
    注意这个时候跳的过程需要做一些改变,每跳到一个位置 (k) 要减去当前节点的 (size),因为做了累加操作,也就是说含有这个子串的个数不止(1),当(k<=0)时即统计完毕

    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #define RG register
    #define il inline
    #define iter iterator
    #define Max(a,b) ((a)>(b)?(a):(b))
    #define Min(a,b) ((a)<(b)?(a):(b))
    using namespace std;
    const int N=1200005;
    char s[N];int fa[N],n,ch[N][27],T,K,len[N],cnt=1,size[N],t[N],p,cur=1;
    void build(int c,int id){
        p=cur;cur=++cnt;len[cur]=id;
        for(;p && !ch[p][c];p=fa[p])ch[p][c]=cur;
        if(!ch[p][c])fa[cur]=1;
        else{
            int q=ch[p][c];
            if(len[p]+1==len[q])fa[cur]=q;
            else{
                int nt=++cnt;len[nt]=len[p]+1;
                memcpy(ch[nt],ch[q],sizeof(ch[q]));
                fa[nt]=fa[q];fa[q]=fa[cur]=nt;
                for(;ch[p][c]==q;p=fa[p])ch[p][c]=nt;
            }
        }
        size[cur]=1;
    }
    int c[N],sa[N];
    void priwork(){
        for(int i=1;i<=cnt;i++)c[len[i]]++;
        for(int i=1;i<=n;i++)c[i]+=c[i-1];
        for(int i=cnt;i>=1;i--)sa[c[len[i]]--]=i;
        for(RG int i=cnt,x;i>=1;i--){
            x=sa[i];
            if(T)size[fa[x]]+=size[x];
            else size[x]=1;
            if(x!=1)t[x]=size[x];
            for(RG int j=0;j<=25;j++)t[x]+=t[ch[x][j]];
        }
    }
    void solve(){
        RG int x=1,u,i;
        while(K>0){
            for(i=0;i<=25;i++){
                if(!ch[x][i])continue;
                u=ch[x][i];
                if(t[u]>=K){
                    putchar(i+'a');
                    x=u;K-=size[x];break;
                }
                else K-=t[u];
            }
        }
    }
    void work()
    {
        scanf("%s%d%d",s+1,&T,&K);
        n=strlen(s+1);
        for(int i=1;i<=n;i++)build(s[i]-'a',i);
        priwork();
        if(t[1]<K){puts("-1");return ;}
        solve();
    }
    
    int main()
    {
    	work();
    	return 0;
    }
    
    
  • 相关阅读:
    网络七层
    微信小程序开发工具 常用快捷键
    BZOJ 1026 windy数 (数位DP)
    BZOJ 1026 windy数 (数位DP)
    CodeForces 55D Beautiful numbers (SPOJ JZPEXT 数位DP)
    CodeForces 55D Beautiful numbers (SPOJ JZPEXT 数位DP)
    HDU 3709 Balanced Number (数位DP)
    HDU 3709 Balanced Number (数位DP)
    UVA 11361 Investigating Div-Sum Property (数位DP)
    UVA 11361 Investigating Div-Sum Property (数位DP)
  • 原文地址:https://www.cnblogs.com/Yuzao/p/7670454.html
Copyright © 2011-2022 走看看