Luogu P2463 [SDOI2008]Sandy的卡片

题目链接 \(Click\) \(Here\)

真的好麻烦啊。。事实证明,理解是理解,一定要认认真真把板子打牢,不然调锅的时候真的会很痛苦。。(最好是八分钟能无脑把\(SA\)码对的程度\(QAQ\)

这个题最开始我想的是\(RMQ\)遍历每一个子区间,但是意识到复杂度是\(O(N^2)\)然后就\(GG\)了。怎么说呢,后缀数组和二分似乎是很常见的组合(和莫队也是?),这个题只需要在\(height\)数组里二分\(lcp\)长度即可,\(check\)函数里面处理一下,要让区间内所有原串都有至少一个子串。

#include <bits/stdc++.h>
using namespace std;

const int N = 200010;

int s[N], id[N];
int n, m, num, len, tot = 10000;
int sa[N], tp[N], rk[N], _rk[N], bin[N], height[N];

void get_height (int n) {
	int k = 0;
	for (int i = 1; i <= n; ++i) {
		if (k != 0) k--;
		int j = sa[rk[i] - 1];
		while (s[i + k] == s[j + k]) k++;
		height[rk[i]] = k;
	}
}

void base_sort (int n, int m) {
	for (int i = 0; i <= m; ++i) bin[i] = 0;
	for (int i = 1; i <= n; ++i) bin[rk[tp[i]]]++;
	for (int i = 1; i <= m; ++i) bin[i] += bin[i - 1];
	for (int i = n; i >= 1; --i) sa[bin[rk[tp[i]]]--] = tp[i];
}

void suffix_sort (int n, int m) {
	for (int i = 1; i <= n; ++i) {
		rk[i] = s[i];
		tp[i] = i;
	}
	base_sort (n, m);
	for (int w = 1; w <= n; w <<= 1) {
		int cnt = 0;
		for (int i = n - w + 1; i <= n; ++i) {
			tp[++cnt] = i;
		}
		for (int i = 1; i <= n; ++i) {
			if (sa[i] > w) {
				tp[++cnt] = sa[i] - w;
			}
		}
		base_sort (n, m);
		memcpy (_rk, rk, sizeof (rk));
		rk[sa[1]] = cnt = 1;
		for (int i = 2; i <= n; ++i) {
			rk[sa[i]] = _rk[sa[i]] == _rk[sa[i - 1]] && _rk[sa[i] + w] == _rk[sa[i - 1] + w] ? cnt : ++cnt;
		}
		if (cnt == n) break;
		m = cnt;
	}
}

bool vis[1010]; int sta[N], top = 0;

bool can_use (int l) {
	while (top) vis[sta[top--]] = false;
	for (int i = 1; i <= len; ++i) {
		if (height[i] < l) {
			while (top) vis[sta[top--]] = false;
		}
		if (!vis[id[sa[i]]]) {
			vis[id[sa[i]]] = true;
			sta[++top] = id[sa[i]];
			if (top == n) return true;
		}
	}
	return false;
}

int main () {
	cin >> n;
	int ban = 2000;
	for (int i = 1; i <= n; ++i) {
		cin >> m;
		for (int j = 1; j <= m; ++j) {
			cin >> s[++len]; //把所有的字符串整合到一个里
			id[len] = i; // 表明主权(len号后缀(的lcp)属于串i)
		}
		s[++len] = ++ban; //隔开
	}
	for (int i = len; i >= 1; --i) {
		s[i] = s[i] - s[i - 1] + 4000;
	}
	suffix_sort (len, 10000);
	get_height (len);
	int l = 0, r = len;
	while (l < r) {
		int mid = (l + r + 1) >> 1;
		if (can_use (mid)) {
			l = mid;
		} else {
			r = mid - 1;
		}
	}
	cout << l + 1 << endl;
}

posted @ 2019-02-26 16:27  maomao9173  阅读(130)  评论(0编辑  收藏  举报