BZOJ3998:[TJOI2015]弦论
Description
对于一个给定长度为N的字符串,求它的第K小子串是什么。
Input
第一行是一个仅由小写英文字母构成的字符串S
第二行为两个整数T和K,T为0则表示不同位置的相同子串算作一个。T=1则表示不同位置的相同子串算作多个。K的意义如题所述。
Output
输出仅一行,为一个数字串,为第K小的子串。如果子串数目不足K个,则输出-1
Sample Input
aabc
0 3
0 3
Sample Output
aab
HINT
N<=5*10^5
T<2
K<=10^9
题解:
原本想写后缀数组的,但到网上搜了一下发现用后缀数组会TLE,于是便学习了后缀自动机。
关于后缀自动机请orz大神犇。
在这道题中,t有两种情况。
对于t=0的情况,每个后缀节点的size为1,记忆化dfs一遍即可。
对于t=1的情况,先把整个字符串输入自动机,将沿途经过的点的初始size赋为1,其余节点赋为0(表示字符串是原串的前缀的情况);
然后沿pre树进行一次dfs,将节点的最终size赋为其pre子树的初始size之和(因为该节点是这些节点的后缀)。
随后像第一种情况一样进行记忆化dfs。
代码:
1 var 2 i,j,l,n,m,now,last,t,cnt:longint; 3 k:int64; 4 a:array[0..1000005,'a'..'z']of int64; 5 pre,v,step,c:array[0..1000005]of longint; 6 size,size2:array[0..1000005]of int64; 7 b:array[0..1000005,1..2]of longint; 8 s:ansistring; 9 ch:char; 10 function ss(x:longint):int64; 11 var i:longint; 12 begin 13 i:=c[x]; 14 while i>0 do begin size[x]:=size[x]+ss(b[i,1]); i:=b[i,2]; end; 15 exit(size[x]); 16 end; 17 procedure ss2(x:longint); 18 var i:char; 19 begin 20 if v[x]=1 then exit; 21 v[x]:=1; 22 for i:='a' to 'z' do 23 begin 24 if a[x,i]>0 then 25 begin ss2(a[x,i]); size2[x]:=size2[x]+size2[a[x,i]]; end; 26 end; 27 size2[x]:=size2[x]+size[x]; 28 end; 29 procedure qq(x:longint); 30 var i:char; 31 begin 32 k:=k-size[x]; if k<=0 then exit; 33 for i:='a' to 'z' do 34 begin 35 if(a[x,i]>0)and(k-size2[a[x,i]]<=0)then 36 begin write(i); qq(a[x,i]); break; end; 37 if a[x,i]>0 then k:=k-size2[a[x,i]]; 38 end; 39 end; 40 begin 41 readln(s); 42 readln(t,k); pre[0]:=-1; 43 for i:=1 to length(s) do 44 begin 45 inc(m); now:=m; step[now]:=step[last]+1; size[now]:=1; 46 while(last<>-1)and(a[last,s[i]]=0)do 47 begin a[last,s[i]]:=now; last:=pre[last]; end; 48 if last=-1 then begin pre[now]:=0; last:=now; continue; end; 49 if step[last]+1=step[a[last,s[i]]] then 50 begin pre[now]:=a[last,s[i]]; last:=now; continue; end; 51 j:=a[last,s[i]]; 52 inc(m); a[m]:=a[j]; pre[m]:=pre[j]; step[m]:=step[last]+1; 53 pre[j]:=m; pre[now]:=m; 54 while last<>-1 do 55 begin 56 if a[last,s[i]]=j then a[last,s[i]]:=m else break; 57 last:=pre[last]; 58 end; 59 last:=now; 60 end; 61 for i:=1 to m do 62 begin inc(cnt); b[cnt,1]:=i; b[cnt,2]:=c[pre[i]]; c[pre[i]]:=cnt; end; 63 if t=1 then ss(0) else 64 for i:=1 to m do size[i]:=1; 65 size[0]:=0; 66 ss2(0); 67 if size2[0]<k then writeln(-1)else begin qq(0); writeln; end; 68 end.