zoukankan      html  css  js  c++  java
  • P3975 [TJOI2015]弦论

    题目描述

    为了提高智商,ZJY开始学习弦论。这一天,她在《 String theory》中看到了这样一道问题:对于一个给定的长度为n的字符串,求出它的第k小子串是什么。你能帮帮她吗?

    输入输出格式

    输入格式:

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

    第二行为两个整数t和k,t为0则表示不同位置的相同子串算作一个,t为1则表示不同位置的相同子串算作多个。k的意义见题目描述。

    输出格式:

    输出数据仅有一行,该行有一个字符串,为第k小的子串。若子串数目不足k个,则输出-1。

    输入输出样例

    输入样例#1:
    aabc
    0 3
    输出样例#1: 
    aab
    输入样例#2: 
    aabc
    1 3
    输出样例#2: 
    aa
    输入样例#3:
    aabc
    1 11
    输出样例#3: 
    -1

    说明

    数据范围

    对于10%的数据,n ≤ 1000。

    对于50%的数据,t = 0。

    对于100%的数据,n ≤ 5 × 10^5, t < 2, k ≤ 10^9。

    题解:首先题目有两个要求,t=1,不同位置相同子串看做不同;t=0:,不同位置的相同子串看成相同;

    先对这个串建个SAM,再对所有节点按照maxlen排下序。这样就可以从长到短地总结答案。

    首先对每个节点维护一个当前节点所占的子串个数。假如t=1就按照Parent树里从叶子节点一层一层往上推的顺序,计算每个串出现的次数。t=0就不用管,直接设成1

    这样就可以维护出每个节点往后推会有多少个串。。(直接加起来

    然后在SAM上按照字典序往下匹配就可以了

    参考代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int INF=0x3f3f3f3f;
    const int maxn=1e6+10;
    char s[maxn];
    int k,t;
    struct SAM{//求字典序第K小串 
        int l[maxn<<1],fa[maxn<<1],nxt[maxn<<1][26];
        int last,cnt,c[maxn<<1],siz[maxn<<1],sum[maxn<<1],a[maxn<<1];
        void Init()
        {
            memset(siz,0,sizeof(siz));
            memset(c,0,sizeof(c));
            memset(sum,0,sizeof(sum));
            memset(a,0,sizeof(a));
            last=cnt=1;
            memset(nxt[1],0,sizeof(nxt[1]));
            fa[1]=l[1]=0;
        }
        int NewNode()
        {
            cnt++;
            memset(nxt[cnt],0,sizeof(nxt[cnt]));
            fa[cnt]=l[cnt]=0;
            return cnt;
        }
        void Add(int ch)
        {
            int p=last,np=NewNode();
            last=np; l[np]=l[p]+1;
            siz[np]=1;
            while(p&&!nxt[p][ch]) nxt[p][ch]=np,p=fa[p];
            if(!p) fa[np]=1;
            else
            {
                int q=nxt[p][ch];
                if(l[q]==l[p]+1) fa[np]=q;
                else
                {
                    int nq=NewNode();
                    memcpy(nxt[nq],nxt[q],sizeof(nxt[q]));
                    fa[nq]=fa[q];
                    l[nq]=l[p]+1;
                    fa[np]=fa[q]=nq;
                    while(nxt[p][ch]==q) nxt[p][ch]=nq,p=fa[p];
                }
            }
        }
        void Build()
        {
            int len=strlen(s+1);
            for(int i=1;i<=len;i++) Add(s[i]-'a');
        }
        void topusort()
        {
            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)
            {//t==1:不同位置的相同子串视为不同 
                if(t) siz[fa[a[i]]]+=siz[a[i]];
                else siz[a[i]]=1;//t==0:视为相同 
            }
            siz[1]=0;
            for(int i=cnt;i;--i)
            {
                sum[a[i]]=siz[a[i]];
                for(int j=0;j<26;++j)
                    if(nxt[a[i]][j]) sum[a[i]]+=sum[nxt[a[i]][j]];
            }
        }    
        void dfs()
        {
            if(k>sum[1]){puts("-1");return ;}
            int now=1;
            while(k>0)
            {
                int p=0;
                while(k>sum[nxt[now][p]])
                {
                    k-=sum[nxt[now][p]];
                    p++;
                }
                now=nxt[now][p];
                putchar('a'+p);
                k-=siz[now];
            }
            return ;
        }
    } sam;
    int main()
    {
        scanf("%s%d%d",s+1,&t,&k);
        sam.Init();
        sam.Build(); 
        sam.topusort();
        sam.dfs();
        return 0;
    }
    View Code
  • 相关阅读:
    【Luogu】P2491消防(单调队列)
    【Luogu】P2824排序(二分答案+线段树排序)
    2-k8s笔记-Kubernetes安装配置指南
    1-k8s笔记-Kubernetes入门
    22-MySQL DBA笔记-其他产品的选择
    21-MySQL DBA笔记-高可用性
    20-MySQL DBA笔记-可扩展的架构
    19-MySQL DBA笔记-操作系统、硬件、网络的优化
    18-MySQL DBA笔记-MySQL Server调优
    17-MySQL DBA笔记-应用程序调优
  • 原文地址:https://www.cnblogs.com/csushl/p/10805198.html
Copyright © 2011-2022 走看看