BZOJ3998:[TJOI2015]弦论

Description

对于一个给定长度为N的字符串,求它的第K小子串是什么。

Input

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

第二行为两个整数T和K,T为0则表示不同位置的相同子串算作一个。T=1则表示不同位置的相同子串算作多个。K的意义如题所述。

Output

输出仅一行,为一个数字串,为第K小的子串。如果子串数目不足K个,则输出-1

Sample Input

aabc
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.
View Code
原文地址:https://www.cnblogs.com/GhostReach/p/6292255.html