BZOJ 3998 TJOI2015 弦论 后缀自动机+DAG上的dp
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3998
题意概述:对于一个给定长度为N的字符串,求它的第K小子串是什么,T为0则表示不同位置的相同子串算作一个。T=1则表示不同位置的相同子串算作多个。N<=500000,K<=10^9.
应该是有三种做法的(当然后缀树我还没有看),于是就把这个东西当成后缀自动机的板子了(因为它很裸啊!!!)。
可以注意到当T=0的时候每走动一步的贡献是1,而T=1的时候每走动一步之后的贡献都是走到的这个状态的right集合大小。同时从同一个状态走出去得到的字符串又有很多种,不难想到可以搞个dp表示从这个点出发(包括这个点自己)可以找到的不同子串数(根据T而定)。
有个技巧是根据MAX把所有的状态排序之后就可以欢快地topo图上转移dp啦!(SAM的转移图是一张DAG)
所以还是好好理解一下SAM上的状态和转移吧,,,。。。。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<algorithm> 6 #include<cmath> 7 #include<queue> 8 #include<set> 9 #include<map> 10 #include<vector> 11 #include<cctype> 12 using namespace std; 13 const int MAXN=500005; 14 15 int T,K,n; char S[MAXN]; 16 17 struct SAM{ 18 static const int maxn=500005; 19 static const int sigma_sz=26; 20 int pa[maxn<<1],to[maxn<<1][sigma_sz],mx[maxn<<1],val[maxn<<1]; long long cnt[maxn<<1]; 21 int sz,last,c[maxn],a[maxn<<1]; 22 SAM(){ last=sz=1; memset(to[1],0,sizeof(to[1])); } 23 int newnode(){ 24 memset(to[++sz],0,sizeof(to[sz])); 25 pa[sz]=mx[sz]=val[sz]=cnt[sz]=0; 26 return sz; 27 } 28 void extend(int w){ 29 int p=last,np=newnode(); last=np; 30 pa[np]=mx[np]=cnt[np]=0; 31 mx[np]=mx[p]+1,val[np]=1; 32 while(p&&!to[p][w]) to[p][w]=np,p=pa[p]; 33 if(!p) pa[np]=1; 34 else{ 35 int q=to[p][w]; 36 if(mx[p]+1==mx[q]) pa[np]=q; 37 else{ 38 int nq=newnode(); mx[nq]=mx[p]+1; 39 memcpy(to[nq],to[q],sizeof(to[nq])); 40 pa[nq]=pa[q]; 41 pa[np]=pa[q]=nq; 42 while(p&&to[p][w]==q) to[p][w]=nq,p=pa[p]; 43 } 44 } 45 } 46 void ready(){ 47 for(int i=1;i<=sz;i++) c[mx[i]]++; 48 for(int i=1;i<=n;i++) c[i]+=c[i-1]; 49 for(int i=sz;i>0;i--) a[c[mx[i]]--]=i; 50 for(int i=sz;i>0;i--){ 51 if(T) val[pa[a[i]]]+=val[a[i]]; 52 else val[a[i]]=1; 53 } 54 val[1]=0; 55 for(int i=sz;i>0;i--){ 56 cnt[a[i]]=val[a[i]]; 57 for(int j=0;j<26;j++) cnt[a[i]]+=cnt[to[a[i]][j]]; 58 } 59 } 60 void dfs(int i){ 61 if(val[i]>=K) return; 62 K-=val[i]; 63 for(int j=0;j<26;j++) if(to[i][j]){ 64 if(cnt[to[i][j]]>=K){ 65 putchar(j+'a'); dfs(to[i][j]); 66 return; 67 } 68 K-=cnt[to[i][j]]; 69 } 70 } 71 }sam; 72 73 void data_in() 74 { 75 gets(S); 76 scanf("%d%d",&T,&K); 77 } 78 void work() 79 { 80 n=strlen(S); 81 for(int i=0;i<n;i++) sam.extend(S[i]-'a'); 82 sam.ready(); 83 if(sam.cnt[1]<K) printf("%d\n",-1); 84 else sam.dfs(1); 85 } 86 int main() 87 { 88 data_in(); 89 work(); 90 return 0; 91 }