BZOJ 3998: [TJOI2015]弦论 后缀自动机 后缀自动机求第k小子串

http://www.lydsy.com/JudgeOnline/problem.php?id=3998

后缀自动机应用的一个模板?需要对len进行一个排序之后再统计每个出现的数量,维护的是以该字符串为前缀的字符串数量和某字符串的出现数量。

wa了两次,写题时犯得错误有:

1.使用样例检查出来向下搜索字符串时没有减去字符串本身出现的数量,比如样例中aabc 0 3,不计重复的情况下向下搜索还要多减一下a和aa分别出现的1次;

2.第一次wa检查出来val没有在建自动机的时候赋值,所以T=1的时候val和g都=0;

3.第二次wa检查半天自己随便打了个字符串跑一下发现数量不对,然后找了半天最后看出来是自己的ac自动机写错了一个len的赋值,太zz了orz。

还是要熟悉一下自动机的写法。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<queue>
 7 using namespace std;
 8 const int maxn=500010;
 9 int siz,T;
10 long long K;
11 char ch[maxn*2]={};
12 int cnt[maxn*2]={};//按照深度排序
13 int b[maxn*2]={};//排序后每个的rk
14 long long val[maxn*2]={};//每个状态出现的数目
15 long long g[maxn*2]={};//每个状态及其所有以其为前缀后继的数目
16 struct nod{
17     int sig[26];
18     int f,len;
19     void cle(){f=-1;len=0;memset(sig,-1,sizeof(sig));}
20 }t[maxn*2];
21 int las=0,tot=0;
22 void add(int z){
23     int x=++tot; t[x].cle();
24     t[x].len=t[las].len+1;
25     val[x]=1;
26     int i=las;
27     for(;i!=-1&&t[i].sig[z]==-1;i=t[i].f)
28         t[i].sig[z]=x;
29     if(i==-1)t[x].f=0;
30     else{
31         int p=t[i].sig[z];
32         if(t[p].len==t[i].len+1)t[x].f=p;
33         else{
34             int y=++tot;t[y].cle();
35             t[y]=t[p];
36             t[y].len=t[i].len+1;
37             t[x].f=t[p].f=y;
38             for(;i!=-1&&t[i].sig[z]==p;i=t[i].f)
39                 t[i].sig[z]=y;
40         }
41     }las=x;
42 }
43 void pai(){
44     for(int i=0;i<=tot;i++)++cnt[t[i].len];
45     for(int i=0;i<=siz;i++)if(i)cnt[i]+=cnt[i-1];
46     for(int i=0;i<=tot;i++)b[cnt[t[i].len]--]=i;
47 }
48 void doit(){
49     for(int i=tot+1;i;i--){
50         int z=b[i];
51         if(T&&z)val[t[z].f]+=val[z];
52         else val[z]=1;
53     }
54     val[0]=0;
55     for(int i=tot+1;i;i--){
56         int z=b[i];
57         g[z]=val[z];
58         for(int j=0;j<26;j++)if(t[z].sig[j]!=-1)g[z]+=g[t[z].sig[j]];
59     }
60 }
61 void getit(int x,long long k){
62     if(k<1)return;
63     long long sum=0;
64     for(int i=0;i<26;i++){
65         if(!t[x].sig[i])continue;
66         if(sum<k&&sum+g[t[x].sig[i]]>=k){
67             printf("%c",'a'+i);
68             getit(t[x].sig[i],k-sum-val[t[x].sig[i]]);
69             break;
70         }sum+=g[t[x].sig[i]];
71     }
72 }
73 int main(){
74     t[0].cle();
75     scanf("%s",ch);siz=strlen(ch);
76     for(int i=0;i<siz;i++)add(int(ch[i]-'a'));
77     pai();
78     scanf("%d%lld",&T,&K);
79     doit();
80     if(K>g[0])printf("-1\n");
81     else getit(0,(long long)K);
82     return 0;
83 }
View Code

 

posted @ 2018-03-12 10:28  鲸头鹳  阅读(155)  评论(0编辑  收藏  举报