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
Source
众人:快看DQS个傻X连个裸题都WA两遍
窝:我不做人辣(╯‵□′)╯︵┻━┻
好吧这真的是裸题……par树原图傻傻分不清楚……
求字典序k小子串。
求出每个点往后可以到达多少个子串p -> sz,然后求k小的时候拿k和当前节点p的sz比较就知道该怎么走了…
想求出来sz,需要知道到达这个点的串的数量,记为cnt,在自动机上跑逆拓扑序用cnt求sz(相当于在树上求子树大小)
然后对于T的两个情况,初始时的cnt就不一样了。若相同的串不同位置算一个,那么每个点代表的串都是1;若不同位置算好多个,那么走到当前点p的子串数量就要加上par指针指向p的串的数量。
然后再在自动机上【不是par树上!】累加sz。
想了想我还是把调试信息删干净再发博客吧……
第二发WA是把答案计数的tot开成char这种事我才不会说呢…
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int SZ = 1000010;
struct sam_node{
sam_node *ch[30],*par;
int val,cnt,sz;
}T[SZ], *root, *last;
int Tcnt = 0,TT;
sam_node* newnode(int x)
{
sam_node *k = T + (Tcnt ++);
k -> val = x;
k -> cnt = k -> sz = 0;
memset(k -> ch,0,sizeof(k -> ch));
k -> par = 0;
return k;
}
void insert(int x)
{
sam_node *p = last,*np = newnode(last -> val + 1);
while(p && !p -> ch[x])
p -> ch[x] = np,p = p -> par;
if(!p)
np -> par = root;
else
{
sam_node *q = p -> ch[x];
if(q -> val == p -> val + 1)
np -> par = q;
else
{
sam_node *nq = newnode(p -> val + 1);
memcpy(nq -> ch,q -> ch,sizeof(nq -> ch));
nq -> par = q -> par;
np -> par = q -> par = nq;
while(p && p -> ch[x] == q)
p -> ch[x] = nq,p = p -> par;
}
}
last = np;
last -> cnt ++;
}
queue<sam_node*> q;
sam_node *S[SZ];
int top = 0;
int in[SZ];
void get_cnt()
{
for(int i = 0;i < Tcnt;i ++)
{
sam_node *p = T + i;
for(int j = 1;j <= 26;j ++)
if(p -> ch[j])
in[p -> ch[j] - T] ++;
}
q.push(root);
while(q.size())
{
sam_node *p = q.front(); q.pop();
S[++ top] = p;
for(int i = 1;i <= 26;i ++)
if(p -> ch[i] && !--in[p -> ch[i] - T])
q.push(p -> ch[i]);
}
int t = top;
while(t)
{
sam_node *p = S[t --];
if(TT && p -> par)
p -> par -> cnt += p -> cnt;
else
p -> cnt = 1;
}
root -> cnt = 0;
t = top;
while(t)
{
sam_node *p = S[t --];
p -> sz = p -> cnt;
for(int j = 1;j <= 26;j ++)
if(p -> ch[j])
p -> sz += p -> ch[j] -> sz;
}
}
char ans[SZ];
int tot = 0;
void dfs(sam_node *p,int k)
{
if(k <= p -> cnt) return ;
k -= p -> cnt;
for(int i = 1;i <= 26;i ++)
if(p -> ch[i])
{
sam_node *q = p -> ch[i];
if(q -> sz >= k)
{
ans[++ tot] = i + 'a' - 1;
dfs(q,k);
return ;
}
k -= q -> sz;
}
}
void init()
{
root = newnode(0);
last = root;
}
char s[SZ];
int main()
{
init();
int k;
scanf("%s%d%d",s,&TT,&k);
int l = strlen(s);
for(int i = 0;i < l;i ++)
insert(s[i] - 'a' + 1);
get_cnt();
if(k > root -> sz)
puts("-1");
else
{
dfs(root,k);
printf("%s",ans + 1);
}
return 0;
}
/*
aaaaa
1 4
*/