zoukankan      html  css  js  c++  java
  • dtoi2572 弦论(string)

    题意:

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

    题解:

         对于本题,首先我们要做的事情是先建立后缀自动机。

         如果T=0,那么每一个位置的出现次数直接设为1,T=1否则就是正常的right集合大小。

         那么我们可以再记一个sum[i],表示从i出发能走多少个串。

         那么我们只需要从a~z依次枚举下一个位置的字母,然后类似于可持久化线段树那样判断一下k是否小于等于sum[nex[i]],如果是就走它,否则k减掉他,继续枚举下一个字母,当k<=当前位置代表的字符串出现的次数的时候停下来即可。

    #include<algorithm>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    char s[500002];
    int cur=1,cnt=1,n,t,k,last,ch[1000002][27],fa[1000002],dis[1000002],q[500002],st[1000002];
    long long sum[1000002],v[1000002];
    bool fl[1000002];
    void build(int c,int id){
        last=cur;cur=++cnt;
        int p=last;dis[cur]=id;
        for (;p&&!ch[p][c];p=fa[p])ch[p][c]=cur;
        if (!p)fa[cur]=1;
        else
        {
            int q=ch[p][c];
            if (dis[q]==dis[p]+1)fa[cur]=q;
            else
            {
                int nt=++cnt;dis[nt]=dis[p]+1;
                for (int i=0;i<26;i++)
                ch[nt][i]=ch[q][i];
                fa[nt]=fa[q];fa[q]=fa[cur]=nt;
                for (;ch[p][c]==q;p=fa[p])ch[p][c]=nt;
            }
        }
        v[cur]=1;
    }
    void dfs(int x){
        if (fl[x])return;
        fl[x]=1;sum[x]=v[x];
        for (int i=0;i<26;i++)
        if (ch[x][i]){dfs(ch[x][i]);sum[x]+=sum[ch[x][i]];}
    }
    int main()
    {
        scanf("%s%d%d",s+1,&t,&k);n=strlen(s+1);
        for(int i=1;i<=n;i++)build(s[i]-'a',i);
        for (int i=1;i<=cnt;i++)q[dis[i]]++;
        for (int i=1;i<=n;i++)q[i]+=q[i-1];
        for (int i=1;i<=cnt;i++)st[q[dis[i]]--]=i;
        for (int i=cnt;i>=1;i--)
        {
            if (t==1)v[fa[st[i]]]+=v[st[i]];
            else v[i]=1;
        }
        v[1]=0;dfs(1);
        if (sum[1]<k){puts("-1");return 0;}
        int rt=1;
        while(1)
        {
            if (k<=v[rt])break;else k-=v[rt];
            bool u=0;int son;
            for (int i=0;i<26;i++)
            if (ch[rt][i])
            {
                u=1;
                if (sum[ch[rt][i]]<k)k-=sum[ch[rt][i]];
                else {printf("%c",i+'a');son=ch[rt][i];break;}
            }
            if (!u)break;
            rt=son;
        }
        return 0;
    }
  • 相关阅读:
    二叉树中序遍历
    前序遍历
    配置免秘钥登录
    pip安装
    zookeeper C client API 和zkpython 的安装
    安装 Java
    json递归查询
    php 编译安装
    docker 中 安装配置 mysqlcluster(arm)
    glibc编译安装
  • 原文地址:https://www.cnblogs.com/1124828077ccj/p/12302915.html
Copyright © 2011-2022 走看看