[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

Solution

后缀自动机模板题。

先建出后缀自动机,预处理出\(sum[i]\)表示从自动机上的\(i\)点出发可以得到多少个串。

要预处理这个,先要预处理出\(sz[i]\)表示自动机上第\(i\)个点代表的\(endpos\)集合的大小。

对于\(T=0\),直接每个\(sz[i]=1\)就行了,否则就在\(parent\)树上递推就好了。

然后得到这个就可以在自动机上递推\(sum[i]\)了。

tips:后缀自动机的\(toposort\)可以按\(maxl\)进行桶排得到。

#include<bits/stdc++.h>
using namespace std;
 
void read(int &x) {
    x=0;int f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
 
void print(int x) {
    if(x<0) putchar('-'),x=-x;
    if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}

const int maxn = 1e6+10;

char s[maxn];
int qs=1,cnt=1,lstp=1,n,T,rk;
int tr[maxn][27],par[maxn],ml[maxn],sz[maxn],r[maxn],t[maxn],sum[maxn];

void append(int c) {
	int p=lstp,np=++cnt;ml[np]=ml[p]+1;lstp=np;sz[np]=1;
	for(;p&&tr[p][c]==0;p=par[p]) tr[p][c]=np;
	if(!p) return par[np]=qs,void();
	int q=tr[p][c];
	if(ml[p]+1<ml[q]) {
		int nq=++cnt;ml[nq]=ml[p]+1;
		memcpy(tr[nq],tr[q],sizeof tr[nq]);
		par[nq]=par[q],par[q]=par[np]=nq;
		for(;p&&tr[p][c]==q;p=par[p]) tr[p][c]=nq;
	}else par[np]=q;
}

void print(int x,int k) {
	if(k>sz[x]) k-=sz[x];
	else return ;
	for(int i=1;i<=26;i++)
		if(tr[x][i]) {
			if(k>sum[tr[x][i]]) k-=sum[tr[x][i]];
			else {
				putchar(i+'a'-1);
				print(tr[x][i],k);break;
			}
		}
}

int main() {
	scanf("%s",s+1);n=strlen(s+1);
	for(int i=1;i<=n;i++) append(s[i]-'a'+1);
	
	for(int i=1;i<=cnt;i++) t[ml[i]]++;
	for(int i=1;i<=n;i++) t[i]+=t[i-1];
	for(int i=1;i<=cnt;i++) r[t[ml[i]]--]=i;

	read(T),read(rk);
	for(int i=cnt;i;i--) T?sz[par[r[i]]]+=sz[r[i]]:sz[r[i]]=1;
	sz[qs]=0;
	for(int i=cnt;i;i--) {
		sum[r[i]]=sz[r[i]];
		for(int j=1;j<=26;j++) if(tr[r[i]][j]) sum[r[i]]+=sum[tr[r[i]][j]];
	}
	
	if(sum[1]>=rk) print(1,rk),puts("");else puts("-1");
	return 0;
}
posted @ 2019-02-25 21:29  Hyscere  阅读(122)  评论(0编辑  收藏  举报