BZOJ 3998 [ZJOI2015]弦论

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

Solution

SAM裸题,蒟蒻实在太弱了,BFS求right不会…无奈只好写了个DFS求right和sum,速度比较慢。。。

第一遍交还MLE了…原来是edge数组申请的太大了。。。

Code

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
#include <cstdio>
const int sigma = 26;
const int size = 1000005;

struct problemSolver {
	int go[size][sigma], par[size], len[size], tot, root, last, ri[size], sum[size];
	int T, K;
	struct edge_type {
		int to, next;
	} edge[size];
	int h[size], cnte;
	char str[size/2];
	void ins(int u, int v) {
		edge[++cnte].to = v;
		edge[cnte].next = h[u];
		h[u] = cnte;
	}
	int newnode(int l) {
		len[++tot] = l;
		par[tot] = 0;
		return tot;
	}
	void init() {
		scanf("%s", str);
		scanf("%d%d", &T, &K);
		tot = 0;
		cnte = 1;
		last = root = newnode(0);
	}
	void extend(int x) {
		int p = last, np = newnode(len[p] + 1);
		ri[np] = 1;
		while (p && go[p][x] == 0) {
			go[p][x] = np;
			p = par[p];
		}
		if (p == 0) {
			par[np] = root;
		} else {
			int q = go[p][x];
			if (len[q] == len[p] + 1) {
				par[np] = q;
			} else {
				int nq = newnode(len[p] + 1);
				par[nq] = par[q];
				for (int i = 0; i < sigma; ++i) go[nq][i] = go[q][i];
				par[np] = par[q] = nq;
				while (p && go[p][x] == q) {
					go[p][x] = nq;
					p = par[p];
				}
			}
		}
		last = np;
	}
	int dfs10(int now) {
		ri[now] = 1;
		for (int i = h[now]; i; i = edge[i].next) dfs10(edge[i].to);
		return 1;
	}
	int dfs11(int now) {
		for (int i = h[now]; i; i = edge[i].next) ri[now] += dfs11(edge[i].to);
		return ri[now];
	}
	int dfs2(int now) {
		if (sum[now]) return sum[now];
		sum[now] = ri[now];
		for (int i = 0; i < sigma; ++i) if (go[now][i]) sum[now] += dfs2(go[now][i]);
		return sum[now];
	}
	void dfs3(int now, int nowK) {
		if (nowK <= ri[now]) return;//
		nowK -= ri[now];//
		for (int i = 0; i < sigma; ++i) {
			if (nowK > sum[go[now][i]]) nowK -= sum[go[now][i]];
			else {
				printf("%c", i+'a');
				dfs3(go[now][i], nowK);
				return;
			}
		}
	}
	void pre() {
		for (int i = 0; str[i]; ++i) extend(str[i] - 'a');
		for (int i = 2; i <= tot; ++i) ins(par[i], i);
		if (T) dfs11(1); else dfs10(1);
		ri[1] = 0;
		for (int i = 1; i <= tot; ++i) dfs2(i);
	}
	void solve() {
		if (sum[1] < K) printf("-1");
		else dfs3(1, K);
	}
} MagHSK;

int main() {
	MagHSK.init();
	MagHSK.pre();
	MagHSK.solve();
}