P3975 [TJOI2015]弦论

(color{#0066ff}{ 题目描述 })

为了提高智商,ZJY开始学习弦论。这一天,她在《 String theory》中看到了这样一道问题:对于一个给定的长度为n的字符串,求出它的第k小子串是什么。你能帮帮她吗?

(color{#0066ff}{输入格式})

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

第二行为两个整数t和k,t为0则表示不同位置的相同子串算作一个,t为1则表示不同位置的相同子串算作多个。k的意义见题目描述。

(color{#0066ff}{输出格式})

输出数据仅有一行,该行有一个字符串,为第k小的子串。若子串数目不足k个,则输出-1。

(color{#0066ff}{输入样例})

aabc
0 3


aabc
1 3


aabc
1 11

(color{#0066ff}{输出样例})

aab

aa

-1

(color{#0066ff}{数据范围与提示})

对于10%的数据,n ≤ 1000。

对于50%的数据,t = 0。

对于100%的数据,n ≤ 5 × 10^5, t < 2, k ≤ 10^9。

(color{#0066ff}{ 题解 })

求第k小字串,SAM上贪心跑就行

但是有一些限制

一个是相同的算一个, 一个是相同的算多个

如果算多个,就要算出字串出现次数(鸡排倒推siz)

贪心的时候不能再-1,要减siz(siz个相同的)

然而。。。MLE

本题及其卡指针

写大鸡排5个点MLE

写toposort1个点MLE

幸好上帝还开了一扇窗---->数据水!!!

TM数组少开100000居然A了(雾~

#include<bits/stdc++.h>
using namespace std;
#define LL long long
LL in() {
	char ch; int x = 0, f = 1;
	while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
	for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
	return x * f;
}
const int maxn = 9e5 + 1;
int type;
struct SAM {
protected:
	struct node {
		node *ch[26], *fa;
		int len, siz, num, du;
		node(int len = 0, int siz = 0, int num = 0, int du = 0): fa(NULL), len(len), siz(siz), num(num), du(du) {
			memset(ch, 0, sizeof ch);
		}
	};
	node *root, *tail, *lst;
	node pool[maxn];
	int in[maxn];
	void extend(int c) {
		node *o = new(tail++) node(lst->len + 1, 1), *v = lst;
		for(; v && !v->ch[c]; v = v->fa) v->ch[c] = o;
		if(!v) o->fa = root;
		else if(v->len + 1 == v->ch[c]->len) o->fa = v->ch[c];
		else {
			node *n = new(tail++) node(v->len + 1), *d = v->ch[c];
			std::copy(d->ch, d->ch + 26, n->ch);
			n->fa = d->fa, d->fa = o->fa = n;
			for(; v && v->ch[c] == d; v = v->fa) v->ch[c] = n;
		}
		lst = o;
	}
	void clr() {
		tail = pool;
		root = lst = new(tail++) node();
	}
	void getnum(node *o) {
		if(o->num) return;
		o->num = type? o->siz : 1;
		for(int i = 0; i <= 25; i++) if(o->ch[i]) getnum(o->ch[i]), o->num += o->ch[i]->num;
	}
	void kth(node *o, int k) {
		if(!k) return;
		for(int i = 0; i <= 25; i++) {
			if(o->ch[i]) {
				if(o->ch[i]->num >= k) {
					putchar((char)i + 'a');
					kth(o->ch[i], type? k - o->ch[i]->siz : k - 1);
					return;
				}
				else k -= o->ch[i]->num;
			}
		}
	}

public:
	SAM() { clr(); }
	void ins(char *s) { for(char *p = s; *p; p++) extend(*p - 'a'); }
	void getnum() { getnum(root); }
	void getsiz() {
		for(node *o = pool; o != tail; o++) if(o->fa) o->fa->du++;
		std::queue<node*> q;
		while(!q.empty()) q.pop();
		for(node *o = pool; o != tail; o++) if(!o->du) q.push(o);
		while(!q.empty()) {
			node *o = q.front(); q.pop();
			if(o->fa) {
				o->fa->siz += o->siz;
				o->fa->du--;
				if(!o->fa->du) q.push(o->fa);
			}
		}
	}
	void kth(int k) { return kth(root, k); }
}sam;
char s[maxn];
int main() {
	scanf("%s", s);
	type = in();
	sam.ins(s);
	sam.getsiz();
	sam.getnum();
	sam.kth(in());
	return 0;
}
原文地址:https://www.cnblogs.com/olinr/p/10255809.html