社区讨论

神秘并查集做法 求条或证伪或hack

P5341[TJOI2019] 甲苯先生和大中锋的字符串参与者 2已保存回复 2

讨论操作

快速查看讨论及其快照的属性,并进行相关操作。

当前回复
2 条
当前快照
1 份
快照标识符
@mjydamsk
此快照首次捕获于
2026/01/03 21:57
2 个月前
此快照最后确认于
2026/01/07 19:45
上个月
查看原帖
85pts85pts 大概思路是先做一个 SA,然后从大到小枚举每一个长度 ll,将所有 hi>=lh_i >= l(i,i1)(i, i - 1) 合并,并维护连通块大小表示出现次数,维护大小为 kk 的连通块的数量,最后答案取最大值。
CPP
#include<bits/stdc++.h>
#define int long long

using namespace std;
using ll = long long;

const int N = 2e5 + 5;

int T, n, m, k, ans, cnt, mx;
int x[N], c[N], y[N], sa[N], rk[N], h[N], f[N], sz[N], id[N];
string s;

void Clear() {
	m = 'z';
	ans = -1;
	cnt = mx = 0;
	for (int i = 1; i <= max(n, m); i++) {
		c[i] = 0;
	}
	for (int i = 1; i <= n; i++) {
		x[i] = y[i] = sa[i] = rk[i] = h[i] = f[i] = sz[i] = id[i] = 0;
	}
	return ;
}

void Sort() {
	for (int i = 1; i <= n; i++) x[i] = s[i], c[x[i]]++;
	for (int i = 1; i <= m; i++) c[i] += c[i - 1];
	for (int i = n; i >= 1; i--) sa[c[x[i]]--] = i;
	for (int k = 1; k < n; k <<= 1) {
		int p = 0;
		for (int i = n - k + 1; i <= n; i++) y[++p] = i;
		for (int i = 1; i <= n; i++) {
			if (sa[i] > k) y[++p] = 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 = 1; i <= m; i++) c[i] += c[i - 1];
		for (int i = n; i >= 1; i--) sa[c[x[y[i]]]--] = y[i], y[i] = 0;
		swap(x, y);
		p = x[sa[1]] = 1;
		for (int i = 2; i <= n; i++) {
			if (y[sa[i]] != y[sa[i - 1]] || y[sa[i] + k] != y[sa[i - 1] + k]) p++;
			x[sa[i]] = p;
		}
		m = p;
		if (n == m) return ;
	}
	return ;
} 

void 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];
		for (; i + k <= n && j + k <= n && s[i + k] == s[j + k]; k++) ;
		h[rk[i]] = k;
	}
	return ;
}

int Cmp(int a, int b) {
	return h[a] > h[b];
}

int Find(int x) {
	return f[x] == x ? x : f[x] = Find(f[x]);
}

void Merge(int x, int y) {
	int fx = Find(x), fy = Find(y);
	if (fx == fy) {
		return ;
	}
	if (sz[fx] > sz[fy]) {
		swap(fx, fy);
	}
	cnt -= sz[fy] == k;
	cnt -= sz[fx] == k;
	f[fx] = fy;
	sz[fy] += sz[fx];
	cnt += sz[fy] == k;
	return ;
}

void Solve() {
	Clear();
	cin >> s >> k;
	n = s.size();
	s = '#' + s;
	Sort(); 
	Height();
	for (int i = 1; i <= n; i++) {
		id[i] = f[i] = i, sz[i] = 1;
	}
//	cout << "------\n";
//	for (int i = 1; i <= n; i++) {
//		cout << sa[i] << ' ' << h[i] << '\n';
//	}
	sort(id + 1, id + 1 + n, Cmp); 
//	cout << "------\n";
//	for (int i = 1; i <= n; i++) {
//		cout << id[i] << ' ' << h[id[i]] << '\n';
//	}
	for (int i = n, j = 1; i >= 1; i--) {
		cnt += sz[n - i + 1] == k;
		for (; j <= n && h[id[j]] >= i; j++) Merge(id[j] - 1, id[j]);
		if (cnt > mx) {
			mx = cnt;
			ans = i;
		}
//		cout << cnt << ' ' << j - 1 << '\n';
	} 
	cout << ans << '\n';
	return ;
}

signed main() {
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	for (cin >> T; T--; Solve()) ;
	return 0;
}

回复

2 条回复,欢迎继续交流。

正在加载回复...