【bzoj3998】 TJOI2015—弦论

http://www.lydsy.com/JudgeOnline/problem.php?id=3998 (题目链接)

题意

  给出一个字符串,求它的字典序第K小的子串是什么,分情况讨论不在同一位置的相同子串需不需要重复考虑。

Solution

  对于不需要重复考虑的情况,直接就是spoj上的那道例题,而需要重复考虑的情况不过就是预处理sum的时候每次加上的是当前节点的right集合大小。

代码

// bzoj3998
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cmath>
#include<set>
#define LL long long
#define inf 1<<30
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;
 
const int maxn=500010;
int n,T,K;
char s[maxn],ans[maxn];

namespace SAM {
	int last,Dargen,sz,n;
	int len[maxn<<1],ch[maxn<<1][26],par[maxn<<1];
	int b[maxn],id[maxn<<1],sum[maxn<<1],r[maxn<<1];
	void Extend(int c) {
		int np=++sz,p=last;last=np;
		len[np]=len[p]+1;
		for (;p && !ch[p][c];p=par[p]) ch[p][c]=np;
		if (!p) par[np]=Dargen;
		else {
			int q=ch[p][c];
			if (len[q]==len[p]+1) par[np]=q;
			else {
				int nq=++sz;len[nq]=len[p]+1;
				memcpy(ch[nq],ch[q],sizeof(ch[q]));
				par[nq]=par[q];
				par[np]=par[q]=nq;
				for (;p && ch[p][c]==q;p=par[p]) ch[p][c]=nq;
			}
		}
	}
	void build() {
		last=Dargen=sz=1;
		n=strlen(s+1);
		for (int i=1;i<=n;i++) Extend(s[i]-'a');
	}
	void pre() {
		for (int i=1;i<=sz;i++) b[len[i]]++;
		for (int i=1;i<=n;i++) b[i]+=b[i-1];
		for (int i=1;i<=sz;i++) id[b[len[i]]--]=i;
		if (!T) {
			for (int i=1;i<=sz;i++) r[i]=1;
			for (int S=0,i=sz;i>=1;i--,S=0) {
				for (int j=0;j<26;j++) if (ch[id[i]][j]) S+=sum[ch[id[i]][j]];
				sum[id[i]]=S+1;
			}
		}
		else {
			for (int p=Dargen,i=1;i<=n;i++) p=ch[p][s[i]-'a'],r[p]++;
			for (int i=sz;i>=1;i--) r[par[id[i]]]+=r[id[i]];
			for (int S=0,i=sz;i>=1;i--,S=0) {
				for (int j=0;j<26;j++) if (ch[id[i]][j]) S+=sum[ch[id[i]][j]];
				sum[id[i]]=S+r[id[i]];
			}
		}
	}
	void query() {
		int tot=0,p=Dargen;
		while (K>0) {
			for (int i=0;i<26;i++) if (ch[p][i]) {
					if (sum[ch[p][i]]>=K) {
						p=ch[p][i];K-=r[p];
						ans[++tot]=i+'a';
						break;
					}
					else K-=sum[ch[p][i]];
				}
		}
		ans[++tot]='\0';
	}	
}
using namespace SAM;

int main() {
	scanf("%s",s+1);
	scanf("%d%d",&T,&K);
	build();
	pre();
	query();
	puts(ans+1);
	return 0;
}

 

posted @ 2017-01-16 10:41  MashiroSky  阅读(198)  评论(0编辑  收藏  举报