其他分享
首页 > 其他分享> > bzoj 3998: [TJOI2015]弦论

bzoj 3998: [TJOI2015]弦论

作者:互联网

可重复与不可重复的第k小串

/**************************************************************
    Problem: 3998
    User: lxy8584099
    Language: C++
    Result: Accepted
    Time:5868 ms
    Memory:126324 kb
****************************************************************/
 
// luogu-judger-enable-o2
#include<cstdio>
#include<cstring>
using namespace std;
const int N=5e5+50;
struct Point {int fa,len,ch[26];} d[N<<1];
int tot=1,last=1,n,k,p,a[N<<1],b[N<<1],size[N<<1],sum[N<<1];
char s[N];
void insert(int c)
{
    int x=last,nx=last=++tot;
    d[nx].len=d[x].len+1; size[nx]=1;
    for(;x&&!d[x].ch[c];x=d[x].fa) d[x].ch[c]=nx;
    if(!x) d[nx].fa=1;
    else
    {
        int y=d[x].ch[c];
        if(d[y].len==d[x].len+1) d[nx].fa=y;
        else
        {
            int ny=++tot; d[ny]=d[y]; 
            d[ny].len=d[x].len+1; d[y].fa=d[nx].fa=ny;
            for(;x&&d[x].ch[c]==y;x=d[x].fa) d[x].ch[c]=ny;
        }
    }
}
int main()
{
    scanf("%s",s+1); n=strlen(s+1);
    scanf("%d%d",&k,&p);
    for(int i=1;i<=n;i++) insert(s[i]-'a');
    for(int i=1;i<=tot;i++) b[d[i].len]++;
    for(int i=1;i<=tot;i++) b[i]+=b[i-1];
    for(int i=1;i<=tot;i++) a[b[d[i].len]--]=i;
// 以上三行操作将反拓扑序存入了数组里 
    for(int i=tot;i>=1;i--)
        if(k) size[d[a[i]].fa]+=size[a[i]];
        else size[a[i]]=1;
// 如果k=0,本质相同的子串在不同位置出现算相同,所以size[i]=1 
// 否则就为endpos集合的大小 即该次 以及之后 会出现多少次
    size[1]=0; // 记得把根节点的size变为0 
    for(int i=tot;i>=1;i--)
    {
        sum[a[i]]=size[a[i]];
        for(int j=0;j<26;j++) if(d[a[i]].ch[j])
            sum[a[i]]+=sum[d[a[i]].ch[j]];
    }
    if(p>sum[1]) {puts("-1");return 0;}
    int u=1; p-=size[1]; while(p>0)
    {
        int l=0; 
        while(p>sum[d[u].ch[l]]) p-=sum[d[u].ch[l++]]; 
        u=d[u].ch[l]; putchar('a'+l); p-=size[u];
    } putchar('\n');
    return 0;
}

 

标签:ch,return,int,弦论,TJOI2015,3998,sum,size
来源: https://www.cnblogs.com/lxy8584099/p/10416520.html