牛客小白月赛77 D-小Why的密码锁(后缀数组)

首先先按后缀排序,求出sa和height

然后按sa从前往后遍历,如果连续的一段都大于等于m的话,就先存在一个小根堆中

当出现一个小于m的话,就从小跟堆中,从小往大找,看最长符合要求的次数是否等于k

如果等于k的话结果++

特判一下k==1的情况

如果k等于1时i,即后缀的第一个数组,只能从1取到n-m+1

特判一下是否会出现多次

然后i从1遍历到n-m+1得出最终结果

const int inf = 0x3f3f3f3f3f3f3f3f, N = 1e6 + 5, mod = 1e9 + 7;
char s[N];
int sa[N], x[N], c[N], y[N];
int rk[N], height[N];
int n, m;
void get_sa() {
	for (int i = 1; i <= n; i++) c[x[i] = s[i]] ++;
	for (int i = 2; i <= m; i++) c[i] += c[i - 1];
	for (int i = n; i; i--) sa[c[x[i]] --] = i;
	for (int k = 1; k <= n; k <<= 1) {
		int num = 0;
		for (int i = n - k + 1; i <= n; i++) y[++num] = i;
		for (int i = 1; i <= n; i++) {
			if (sa[i] > k)
				y[++num] = sa[i] - k;
		}
		for (int i = 1; i <= m; i++) c[i] = 0;
		for (int i = 1; i <= n; i++) c[x[i]]++;
		for (int i = 2; i <= m; i++) c[i] += c[i - 1];
		for (int i = n; i; i--) sa[c[x[y[i]]]--] = y[i], y[i] = 0;
		swap(x, y);
		x[sa[1]] = 1, num = 1;
		for (int i = 2; i <= n; i++)
			x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k] ? num : ++num);
		if (num == n) break;
		m = num;
	}
}
void get_height()
{
	for (int i = 1; i <= n; i++) rk[sa[i]] = i;
	for (int i = 1, k = 0; i <= n; i++)
	{
		if (rk[i] == 1) continue;
		if (k) k--;
		int j = sa[rk[i] - 1];
		while (i + k <= n && j + k <= n && s[i + k] == s[j + k]) k++;
		height[rk[i]] = k;
	}
}
signed main() {
	ios_base::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	int mm, k;
	cin >> n >> mm >> k;
	cin >> s + 1;
	m = '9' + 1;
	get_sa();
	get_height();
	int ans = 0;
	if (k != 1) {
		priority_queue, greater>se;
		for (int i = 1; i <= n; i++) {
			if (height[i] >= mm) {
				if (se.empty()) se.push(sa[i - 1]);
				se.push(sa[i]);
			}
			else {
				if (se.empty()) continue;
				int p = se.top();
				se.pop();
				int cnt = 1;
				while (se.size()) {
					int w = se.top();
					if (w - p >= mm) {
						p = w;
						cnt++;
					}
					se.pop();
				}
				if (cnt == k) ans++;

			}
		}
		int p, cnt;
		if (se.empty()) { goto z; }
		p = se.top();
		se.pop();
		cnt = 1;
		while (se.size()) {
			int w = se.top();
			if (w - p >= mm) {
				p = w;
				cnt++;
			}
			se.pop();
		}
		if (cnt == k) ans++;
	z:;
		cout << ans << '\n';
	}
	else {
		vectorst(n + 1);
		for (int i = 1; i <= n; i++) {
			if (height[i] >= mm) {
				st[sa[i - 1]] = 1;
				st[sa[i]] = 1;
			}
		}
		int ans = 0;
		for (int i = 1; i <= n - mm + 1; i++) {
			if (!st[i]) {
				ans++;
			}
		}
		cout << ans << '\n';
	}
}

你可能感兴趣的:(算法,数据结构)