弦论[TJOI2015]

我们建SAM,在SAM上跑DP:(SAM不会点这里

   当T=1时,cnt.fa+=cnt;(因为这时我们一个点代表了很多的子串。)

   当T=0时,cnt=1

   然后DFS出解。

#include<bits/stdc++.h>
#define N 1000005
using namespace std;
struct po{int len,ch[26],fa;}s[N];
int nq,last=1,cnt[N],sum[N],p,np,tot=1,k,T,len,id[N],c[N];
char ch[N];
inline void Sam(int x){
    nq=++tot; s[nq].len=s[last].len+1;
    for (;last&&!s[last].ch[x];last=s[last].fa) s[last].ch[x]=nq;
    if (!last) s[nq].fa=1; else {
        p=s[last].ch[x];
        if (s[last].len+1==s[p].len) s[nq].fa=p; else {
            np=++tot; s[np]=s[p];
            s[np].len=s[last].len+1;
            s[p].fa=s[nq].fa=np;
            for (;last&&s[last].ch[x]==p;last=s[last].fa) s[last].ch[x]=np;
        }
    } last=nq; cnt[last]=1;
}
void dfs(int x){
    k-=cnt[x];
    if (k<=0) return;
    for (int i=0;i<26;i++)
     if (int t=s[x].ch[i]) {
         if (k<=sum[t]) {putchar('a'+i);dfs(t);return;}
         k-=sum[t];
     }
}
int main () {
    freopen("a.in","r",stdin);
    scanf("%s",ch+1); len=strlen(ch+1);
    for (int i=1;i<=len;i++) 
     Sam(ch[i]-'a');
    for (int i=1;i<=tot;i++) c[s[i].len]++;
    for (int i=1;i<=len;i++) c[i]+=c[i-1];
    for (int i=1;i<=tot;i++) id[c[s[i].len]--]=i;
    scanf("%d%d",&T,&k);
    for (int i=tot;i;i--) T?cnt[s[id[i]].fa]+=cnt[id[i]]:cnt[id[i]]=1; 
    cnt[1]=0;
    for (int i=tot;i;i--) {
        sum[id[i]]=cnt[id[i]];
        for (int j=0;j<26;j++) sum[id[i]]+=sum[s[id[i]].ch[j]];
    }
    if (sum[1]<k)  {puts("-1");return 0;}
    dfs(1); 
    return 0;
}

 

posted @ 2018-01-21 20:07  泪寒之雪  阅读(227)  评论(0编辑  收藏  举报