[bzoj 3998][TJOI2015]弦論
阿新 • • 發佈:2019-01-27
per com 相同 blog bold clu 似的 har color
傳送門
Description
對於一個給定長度為N的字符串,求它的第\(K\)小子串是什麽。
\(T=0\)則表示不同位置的相同子串算作一個。\(T=1\)則表示不同位置的相同子串算作多個。
Solution
\(SAM\)可以用來維護子串的信息,而相類似的子串會由同一個狀態來維護。
當\(T=0\)時,我們發現不需要維護\(Right\)集合的大小,我們不妨直接當它是\(1\)
為了查詢答案,我們需要記錄一下每個狀態後繼的大小和。
Code?
//2019.1.26 23:20~00:07 #include<bits/stdc++.h> #define ll long long #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) #define MN 1000005 int c[MN][26],step[MN],val[MN],fa[MN],siz[MN],v[MN],rk[MN]; int last,cnt,n; inline void init() { last=cnt=1;memset(c,0,sizeof c); register int i; for(i=1;i<n<<1;++i) val[i]=step[i]=fa[i]=0; } void Insert(int x) { int p=last,np=++cnt;step[np]=step[p]+1;val[np]=1; for(;p&&!c[p][x];p=fa[p]) c[p][x]=np; if(!p) fa[np]=1; else { int q=c[p][x]; if(step[q]==step[p]+1) fa[np]=q; else { int nq=++cnt;step[nq]=step[p]+1; memcpy(c[nq],c[q],sizeof c[q]); fa[nq]=fa[q];fa[np]=fa[q]=nq; for(;c[p][x]==q;p=fa[p]) c[p][x]=nq; } } last=np; } inline void work() { register int i; for(i=1;i<=cnt;++i) ++v[step[i]]; for(i=1;i<=n;++i) v[i]+=v[i-1]; for(i=1;i<=cnt;++i) rk[v[step[i]]--]=i; for(i=cnt;i;--i) val[fa[rk[i]]]+=val[rk[i]],siz[rk[i]]=val[rk[i]]; val[1]=siz[1]=0; } char s[MN],ans[MN];int len; inline void dfs(int x,int k) { if(k<=val[x]) return;k-=val[x]; register int i; for(i=0;i<26;++i) if(k>siz[c[x][i]]) k-=siz[c[x][i]]; else {ans[len++]=i+'a',dfs(c[x][i],k);break;} } int main() { register int i,j,k,type; scanf("%s%d%d",s+1,&type,&k);n=strlen(s+1); init(); for(i=1;i<=n;++i) Insert(s[i]-'a'); work(); if(!type) for(i=2;i<=cnt;++i) val[i]=siz[i]=1; for(i=cnt;i;--i)for(j=0;j<26;++j)if(c[rk[i]][j])siz[rk[i]]+=siz[c[rk[i]][j]]; if(siz[1]<k) puts("-1"); else dfs(1,k),printf("%s",ans); return 0; }
Blog來自PaperCloud,未經允許,請勿轉載,TKS!
[bzoj 3998][TJOI2015]弦論