TJOI2015 弦論
阿新 • • 發佈:2018-12-10
題解:
鑑於子串我們很容易想到字尾自動機。
先建字尾自動機,然後處理單點價值以及對於每個點的總價值。
T=0要求去重,此時單點價值為1;
T=0要求不去重,此時單點價值為parent樹上endpos的數量。字尾的字首就是子串。
由於建成的字尾自動機有向無環,我們可以O(n)時間處理每個點的總價值,即sum[u]+=sum[to]。
時間複雜度O(n)。
程式碼:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 500050 #definell long long char s[N]; int T,K; struct Point { int pre,len,trs[28]; }p[2*N]; struct SAM { int siz[2*N],v[2*N]; ll sum[2*N]; int tot,las; SAM(){tot=las=1;} int hed[2*N],cnt; struct EG { int to,nxt; }e[2*N]; void ae(int f,int t) { e[++cnt].to = t; e[cnt].nxt= hed[f]; hed[f] = cnt; } void insert(int c) { int np,nq,lp,lq; np=++tot; siz[np]=1; p[np].len = p[las].len+1; for(lp=las;lp&&!p[lp].trs[c];lp=p[lp].pre) p[lp].trs[c]=np; if(!lp)p[np].pre = 1; else { lq= p[lp].trs[c]; if(p[lq].len==p[lp].len+1)p[np].pre = lq; else { nq = ++tot; p[nq] = p[lq]; p[nq].len = p[lp].len+1; p[lq].pre = p[np].pre = nq; while(p[lp].trs[c]==lq) { p[lp].trs[c]=nq; lp=p[lp].pre; } } } las = np; } void dfs1(int u) { v[u]=T?siz[u]:1; for(int j=hed[u];j;j=e[j].nxt) { int to = e[j].to; dfs1(to); if(T)v[u]+=v[to]; } } void dfs2(int u) { sum[u] = v[u]; for(int i=1;i<=26;i++) { int to = p[u].trs[i]; if(!to)continue; if(!sum[to])dfs2(to); sum[u]+=sum[to]; } } void build() { for(int i=2;i<=tot;i++) ae(p[i].pre,i); dfs1(1); v[1]=0; dfs2(1); } void cal(int k) { int u = 1; if(sum[1]<k) { printf("-1"); return ; } while(1) { for(int i=1;i<=26;i++) { if(k>sum[p[u].trs[i]])k-=sum[p[u].trs[i]]; else { printf("%c",'a'+i-1); u = p[u].trs[i]; k-= v[u]; break; } } if(k<=0)return ; } } }sam; int main() { scanf("%s%d%d",s+1,&T,&K); int len = strlen(s+1); for(int i=1;i<=len;i++) sam.insert(s[i]-'a'+1); sam.build(); sam.cal(K); printf("\n"); return 0; }