[后缀自动机][TJOI2015]弦论

题目描述

为了提高智商,ZJY开始学习弦论。这一天,她在《 String theory》中看到了这样一道问题:对于一个给定的长度为n的字符串,求出它的第k小子串是什么。你能帮帮她吗?

输入输出格式

输入格式:

第一行是一个仅由小写英文字母构成的字符串s

第二行为两个整数t和k,t为0则表示不同位置的相同子串算作一个,t为1则表示不同位置的相同子串算作多个。k的意义见题目描述。

输出格式:

输出数据仅有一行,该行有一个字符串,为第k小的子串。若子串数目不足k个,则输出-1。

输入输出样例

输入样例#1: 
aabc
0 3
输出样例#1: 
aab
输入样例#2: 
aabc
1 3
输出样例#2: 
aa
输入样例#3: 
aabc
1 11
输出样例#3: 
-1

说明

数据范围

对于10%的数据,n ≤ 1000。

对于50%的数据,t = 0。

对于100%的数据,n ≤ 5 × 10^5, t < 2, k ≤ 10^9。

 

题解

构建出SAM之后,求出sum[i],表示有sum[i]个子串经过i号点

siz[i]表示i所代表的Endpos的集合大小,也就是i所对应字符串集合的出现次数

T=0时,本质相同的子串在不同位置出现算相同,所以siz[i]=1,即将每个字符串集合的Endpos集合大小(字符串集合元素出现次数)置为1

T=1时,本质相同的子串在不同位置出现算不同,那么累加后的siz表示实际上Endpos的集合大小

siz是在parent树上统计的  sum是在后缀自动机的DAG上拓扑逆序求得的

 

 1 #include<cstdio>
 2 #include<cstring>
 3 using namespace std;
 4 const int N=500000+15;
 5 int n,tot=1,las=1,siz[2*N];
 6 struct point{int ch[26],ff,len;}t[2*N];
 7 inline void extend(int c)
 8  {int p=las,np=++tot; siz[tot]=1; las=np;
 9   t[np].len=t[p].len+1;
10   while(p&&!t[p].ch[c]) t[p].ch[c]=np,p=t[p].ff;
11   if(!p) t[np].ff=1;
12   else 
13      {int q=t[p].ch[c];
14       if(t[p].len+1==t[q].len) t[np].ff=q;
15       else
16        {int nq=++tot; t[nq]=t[q]; t[nq].len=t[p].len+1;
17         t[q].ff=t[np].ff=nq;
18         while(p&&t[p].ch[c]==q) t[p].ch[c]=nq,p=t[p].ff;
19        }
20      }
21  }
22 char s[N];
23 int num,last[N*2],nxt[2*N],ver[2*N];
24 inline void add(int x,int y) {nxt[++num]=last[x]; last[x]=num; ver[num]=y;}
25 int sum[2*N],tong[2*N],ord[2*N];
26 
27 int main()
28 {int ti,k;
29  scanf("%s%d%d",s+1,&ti,&k); int len=strlen(s+1);    
30  for(int i=1;i<=len;i++) extend(s[i]-'a');
31     
32  for(int i=2;i<=tot;i++) add(t[i].ff,i);    
33     
34     
35  for(int i=1;i<=tot;i++) tong[t[i].len]++;
36  for(int i=1;i<=len;i++) tong[i]+=tong[i-1];
37  for(int i=1;i<=tot;i++)  ord[tong[t[i].len]--]=i;
38  for(int i=tot;i;i--) 
39    if(ti)  siz[t[ord[i]].ff]+=siz[ord[i]];   
40    else    siz[ord[i]]=1;
41  siz[1]=sum[1]=0;
42  
43  
44  
45  for(int i=tot;i;i--)
46   {sum[ord[i]]=siz[ord[i]];
47    for(int j=0;j<26;j++)
48     sum[ord[i]]+=sum[t[ord[i]].ch[j]];
49   }     
50  
51  //for(int i=1;i<=tot;i++) printf("%d ",siz[i]); printf("\n");
52  //   for(int i=1;i<=tot;i++) printf("%d ",sum[i]);    
53  if(k>sum[1]) {printf("-1"); return 0;}
54  int now=1;
55  while((k-=siz[now])>0)
56   {int p=0;
57    while(k>sum[t[now].ch[p]]) k-=sum[t[now].ch[p++]];
58    now=t[now].ch[p];
59    printf("%c",'a'+p);
60   }    
61 return 0;    
62 }

 

 

 

posted @ 2019-04-23 21:13  YuXiaoze  阅读(165)  评论(0编辑  收藏  举报