弦论[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; }