【BZOJ 3998】 3998: [TJOI2015]弦论 (SAM )
3998: [TJOI2015]弦论
Time Limit: 10 Sec Memory Limit: 256 MB
Submit: 2627 Solved: 881Description
对于一个给定长度为N的字符串,求它的第K小子串是什么。
Input
第一行是一个仅由小写英文字母构成的字符串S
第二行为两个整数T和K,T为0则表示不同位置的相同子串算作一个。T=1则表示不同位置的相同子串算作多个。K的意义如题所述。Output
输出仅一行,为一个数字串,为第K小的子串。如果子串数目不足K个,则输出-1
Sample Input
aabc
0 3Sample Output
aab
HINT
N<=5*10^5
T<2
K<=10^9Source
【分析】
建SAM,然后跑。
right数组要按照拓扑序来求啊!!!!
然后累计儿子的和的时候也要用拓扑序。
具体拓扑序:
for(int i=1;i<=tot;i++) v[t[i].step]++; for(int i=1;i<=tot;i++) v[i]+=v[i-1]; for(int i=tot;i>=1;i--) q[v[t[i].step]--]=i;
类似后缀数组那里的了。
T=0,就right一开始都为1;T=1,就用right数组。
空串算一个串,一开始k++。
当然后缀数组也是可以的。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 #define Maxn 500010 8 9 struct node 10 { 11 int pre,last,son[30],step; 12 }t[Maxn*2]; 13 int rt[Maxn*2],sm0[2*Maxn],sm1[2*Maxn]; 14 int v[2*Maxn],q[2*Maxn]; 15 16 struct sam 17 { 18 int last,tot; 19 void extend(int k) 20 { 21 int np=++tot,p=last; 22 t[np].step=t[last].step+1; 23 rt[np]=1; 24 while(p&&!t[p].son[k]) 25 { 26 t[p].son[k]=np; 27 p=t[p].pre; 28 } 29 if(!p) t[np].pre=1; 30 else 31 { 32 int q=t[p].son[k]; 33 if(t[q].step==t[p].step+1) t[np].pre=q; 34 else 35 { 36 int nq=++tot; 37 memcpy(t[nq].son,t[q].son,sizeof(t[nq].son)); 38 t[nq].step=t[p].step+1; 39 t[nq].pre=t[q].pre; 40 t[q].pre=t[np].pre=nq; 41 while(p&&t[p].son[k]==q) 42 { 43 t[p].son[k]=nq; 44 p=t[p].pre; 45 } 46 } 47 } 48 last=np; 49 } 50 void init() 51 { 52 for(int i=1;i<=tot;i++) v[t[i].step]++; 53 for(int i=1;i<=tot;i++) v[i]+=v[i-1]; 54 for(int i=tot;i>=1;i--) q[v[t[i].step]--]=i; 55 56 // for(int i=1;i<=tot;i++) rt[i]=1; 57 // for(int i=tot;i>=1;i--) rt[t[i].pre]+=rt[i]; 58 // rt[1]=1; 59 for(int i=tot;i>=1;i--) 60 { 61 int nw=q[i]; 62 rt[t[nw].pre]+=rt[nw]; 63 }rt[1]=1; 64 65 for(int i=tot;i>=1;i--) 66 { 67 int nw=q[i]; 68 sm0[nw]=1;sm1[nw]=rt[nw]; 69 for(int j=1;j<=26;j++) if(t[nw].son[j]) 70 { 71 sm0[nw]+=sm0[t[nw].son[j]]; 72 sm1[nw]+=sm1[t[nw].son[j]]; 73 } 74 } 75 } 76 void ffind(int opt,int k) 77 { 78 int sm,nw=1; 79 k++; 80 while(1) 81 { 82 sm=opt?rt[nw]:1; 83 for(int i=1;i<=26;i++) if(t[nw].son[i]) 84 { 85 int ss=sm; 86 if(!opt) sm+=sm0[t[nw].son[i]]; 87 else sm+=sm1[t[nw].son[i]]; 88 if(sm>=k) {k-=ss;printf("%c",'a'+i-1);nw=t[nw].son[i];break;} 89 } 90 if(!opt&&k==1) break; 91 if(opt&&k<=rt[nw]) break; 92 } 93 printf("\n"); 94 } 95 }sam; 96 97 char s[Maxn]; 98 99 int main() 100 { 101 scanf("%s",s); 102 int l=strlen(s); 103 sam.last=sam.tot=1; 104 for(int i=0;i<l;i++) sam.extend(s[i]-'a'+1); 105 sam.init(); 106 int opt,k; 107 scanf("%d%d",&opt,&k); 108 if(!opt&&k+1>sm0[1]) printf("-1\n"); 109 else if(opt&&k+rt[1]>sm1[1]) printf("-1\n"); 110 else sam.ffind(opt,k); 111 return 0; 112 }
2017-04-17 13:59:36