1. 程式人生 > >BZOJ 3998 [TJOI2015]弦論 (字尾自動機)

BZOJ 3998 [TJOI2015]弦論 (字尾自動機)

題目大意:

給你一個字串,求字典序第$k$小的串是什麼

先建出$sam$和$parent$樹

在$trs$圖中,從根走向節點x的每一條路徑都是x能代表的一個字串

$parent$樹以 某個節點為根的子樹內$endpos$節點的數量,表示這個節點 能代表的所有字串 正序作為字尾在所有字首串中出現的次數

利用這個性質,我們在$trs$圖中反向拓撲,就能累加出以某個節點x代表的某個字串為字首的子串總數量

因為從一個節點$x$沿一條正向邊$trs[x][i]$走向一個節點$y$,我們能表示的字串就是在$x$原來表示的某個字串$S$之後新增一個字元$i$,是正序的

而反向拓撲是統計$S$後面能接的串$ixxx$的總數量

最後在$trs$圖上26分即可

  1 #include <vector>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #define N1 505000
  6 #define S1 (N1<<1)
  7 #define ll long long
  8 #define uint unsigned int
  9 #define rint register int 
 10 #define il inline 
 11
#define inf 0x3f3f3f3f 12 #define idx(X) (X-'a') 13 using namespace std; 14 15 int gint() 16 { 17 int ret=0,fh=1;char c=getchar(); 18 while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();} 19 while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();} 20 return ret*fh;
21 } 22 23 int T,K,n,m,len,cte; 24 char str[N1]; 25 26 namespace SAM{ 27 int trs[S1][26],pre[S1],dep[S1],ed[S1],la,tot; 28 ll sz[S1],sum[S1]; 29 void init(){tot=la=1;} 30 void Build_SAM(int x) 31 { 32 int p,q,np,nq; 33 np=++tot,p=la,la=np; 34 dep[np]=dep[p]+1,ed[np]=1; 35 for(;p&&!trs[p][x];p=pre[p]) trs[p][x]=np; 36 if(!p) pre[np]=1; 37 else{ 38 q=trs[p][x]; 39 if(dep[q]==dep[p]+1) pre[np]=q; 40 else{ 41 pre[nq=++tot]=pre[q]; 42 pre[np]=pre[q]=nq; 43 dep[nq]=dep[p]+1; 44 memcpy(trs[nq],trs[q],sizeof(trs[q])); 45 for(;p&&trs[p][x]==q;p=pre[p]) trs[p][x]=nq; 46 } 47 } 48 } 49 bool cmp(int x,int y){return x<y;} 50 51 int ret[N1],tp; 52 int hs[S1],que[S1]; 53 void solve() 54 { 55 init(); 56 for(int i=1;i<=len;i++) 57 Build_SAM(idx(str[i])); 58 for(int i=2;i<=tot;i++) 59 hs[dep[i]]++; 60 for(int i=1;i<=len;i++) 61 hs[i]+=hs[i-1]; 62 for(int i=1;i<=tot;i++) 63 que[hs[dep[i]]--]=i; 64 int x; 65 for(int i=tot-1;i>=1;i--) 66 { 67 x=que[i]; 68 sz[x]+=ed[x]?1:0; 69 if(!T) sz[x]=1; 70 else sz[pre[x]]+=sz[x]; 71 } 72 sz[1]=0; 73 for(int i=tot-1;i>=0;i--) 74 { 75 x=que[i]; 76 sum[x]+=sz[x]; 77 for(int j=0;j<26;j++) 78 sum[x]+=sum[trs[x][j]]; 79 } 80 x=1; 81 if(K>sum[1]){printf("-1\n");return;} 82 while(1) 83 { 84 if(K<=sz[x]) {break;} 85 K-=sz[x]; 86 for(int i=0;i<26;i++) 87 { 88 if(K>sum[trs[x][i]]){ 89 K-=sum[trs[x][i]]; 90 }else{ 91 ret[++tp]=i; 92 x=trs[x][i]; 93 break; 94 } 95 } 96 } 97 for(int i=1;i<=tp;i++) 98 printf("%c",ret[i]+'a'); 99 puts(""); 100 } 101 }; 102 103 int main() 104 { 105 //freopen("t2.in","r",stdin); 106 scanf("%s",str+1); 107 len=strlen(str+1); 108 scanf("%d%d",&T,&K); 109 SAM::solve(); 110 return 0; 111 }