bzoj3998: [TJOI2015]弦论
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 #define maxn 1000005 7 #define maxm 500005 8 using namespace std; 9 10 typedef long long ll; 11 ll temp[26],sum[maxn]; 12 int n,t,k,tot,root,last,tmp[maxn],dist[maxn],fa[maxn],son[maxn][26],ri[maxn]; 13 bool bo=0; 14 char st[maxm]; 15 struct Tsegment{ 16 void prepare(){tot=root=last=1;} 17 int newnode(int x){dist[++tot]=x; return tot;} 18 void add(int x){ 19 int p=last,np=newnode(dist[last]+1); last=np; 20 for (;p&&!son[p][x];p=fa[p]) son[p][x]=np; 21 if (p==0) fa[np]=root; 22 else{ 23 int q=son[p][x]; 24 if (dist[p]+1==dist[q]) fa[np]=q; 25 else{ 26 int nq=newnode(dist[p]+1); 27 memcpy(son[nq],son[q],sizeof(son[q])); 28 fa[nq]=fa[q],fa[q]=fa[np]=nq; 29 for (;p&&son[p][x]==q;p=fa[p]) son[p][x]=nq; 30 } 31 } 32 } 33 void dfs(int x,int rank){ 34 if (rank<=0){ 35 bo=1; 36 return; 37 } 38 memset(temp,0,sizeof(temp)); 39 for (int i=0;i<26;i++){ 40 if (i==0) temp[i]=sum[son[x][i]]; 41 else temp[i]=temp[i-1]+sum[son[x][i]]; 42 } 43 for (int i=0;i<26;i++){ 44 if (!son[x][i]) continue; 45 if (temp[i]>=rank){ 46 printf("%c",i+'a'); 47 if (i==0){ 48 if (t==0) dfs(son[x][i],rank-1); 49 else dfs(son[x][i],rank-ri[son[x][i]]); 50 if (bo==1) return; 51 }else{ 52 if (t==0) dfs(son[x][i],rank-1-temp[i-1]); 53 else dfs(son[x][i],rank-ri[son[x][i]]-temp[i-1]); 54 if (bo==1) return; 55 } 56 } 57 } 58 } 59 }SAM; 60 61 int main(){ 62 scanf("%s",st),n=strlen(st); 63 SAM.prepare(); 64 for (int i=0;i<n;i++) SAM.add(st[i]-'a'); 65 memset(sum,0,sizeof(sum)); 66 for (int i=1;i<=tot;i++) sum[dist[i]]++; 67 for (int i=1;i<=n;i++) sum[i]+=sum[i-1]; 68 for (int i=1;i<=tot;i++) tmp[sum[dist[i]]--]=i; 69 scanf("%d%d",&t,&k); 70 last=root; 71 memset(ri,0,sizeof(ri)); 72 for (int i=0;i<n;i++){ 73 int x=st[i]-'a'; 74 last=son[last][x],ri[last]=1; 75 } 76 for (int i=tot;i>=1;i--){ 77 int x=tmp[i]; 78 if (fa[x]) ri[fa[x]]+=ri[x]; 79 } 80 ri[root]=0; 81 memset(sum,0,sizeof(sum)); 82 for (int i=tot;i>=1;i--){ 83 int x=tmp[i]; 84 if (t==0) sum[x]=1; 85 else sum[x]=ri[x]; 86 for (int j=0;j<26;j++){ 87 if (son[x][j]) sum[x]+=sum[son[x][j]]; 88 } 89 } 90 sum[root]=bo=sum[0]=0; 91 SAM.dfs(root,k); 92 if (bo==0) printf("-1\n"); 93 else printf("\n"); 94 return 0; 95 }
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3998
题目大意:对于一个给定长度为N的字符串,求它的第K小子串是什么。
第一行是一个仅由小写英文字母构成的字符串S。
第二行为两个整数T和K,T为0则表示不同位置的相同子串算作一个。T=1则表示不同位置的相同子串算作多个。K的意义如题所述。
做法:看到这题,正解是对这个字符串建立一个后缀自动机,对每个节点记录一个信息:往下面匹配能匹配多少个字符串(在计算是,若t=0,则初始为1,否则初始权值为该节点的right值),最后从root开始贪心即可。
后缀自动机+贪心。