Loading

CF1550E Stringforces (二分+状压 dp)

CF1550E Stringforces

二分+状压 dp

可以看到最大值最小的信息,考虑二分最小值,判断是否存在方案满足条件。

思考答案的最终状态如果只看每个字母最长连续子串的部分形如 aaa...ccc...bbbb...ddd。每个时刻会有一些字符满足条件,所以考虑状压字符集,朴素设 \(f_{i,s}\) 表示考虑到第 \(i\) 个,是否存在满足条件的字符集状态为 \(s\) 的方案。但显然是无法开出这样的数组的。所以我们考虑将 \(i\) 这一位放到 \(f_{i,s}\) 里,也就是\(f_{s}\) 表示满足条件的字符集状态为 \(s\) 的最短长度

转移枚举下一次要满足的字符,那么就要用满足这个字符的最小右端点转移。可以考虑递推预处理出从每 \(i\) 位置开始,满足字符 \(j\) 的最小右端点 \(g_{i,j}\),转移有 \(g_{i,j}=g_{i+1,j}\),还有从当前位开始的连续子串是否可以,这个可以 st 表预处理出区间每个字符代表的二进制的或

转移完后判断 \(f_{lim}\le n\) 即可,那么就完了。

复杂度 \(O(2^v\log n)\)

#include <bits/stdc++.h>
#define pii std::pair<int, int>
#define fi first
#define se second
#define pb push_back

using i64 = long long;
using ull = unsigned long long;
const i64 iinf = 0x3f3f3f3f, linf = 0x3f3f3f3f3f3f3f3f;
const int N = 2e5 + 10, P = 18;
int n, k, ans, lim;
char s[N];
int f[1 << P], a[N][P], lg[N], nxt[N][P];
int qry(int l, int r) {
	int p = lg[r - l + 1];
	return a[l][p] | a[r - (1 << p) + 1][p];
}
bool check(int x) {
	if(!x) return 1;
	for(int i = 0; i < lim; i++) f[i] = n + 1;
	for(int i = 1; i <= n + 2; i++) for(int j = 1; j <= k; j++) nxt[i][j] = n + 1;
	for(int i = n; i >= 1; i--) {
		for(int j = 1; j <= k; j++) {
			nxt[i][j] = nxt[i + 1][j];
			if(i + x - 1 <= n && (qry(i, i + x - 1) == (1 << j) || !qry(i, i + x - 1))) nxt[i][j] = i + x - 1;
		}
	}

	f[0] = 0;
	for(int s = 0; s < lim; s++) {
		for(int j = 0; j < k; j++) {
			if(!(s & (1 << j))) {
				f[s | (1 << j)] = std::min(f[s | (1 << j)], nxt[f[s] + 1][j + 1]);
			}
		}
	}
	return f[lim - 1] <= n;
}
void solve() {
	std::cin >> n >> k;
	lim = (1 << k);
	std::cin >> s + 1;

	for(int i = 1; i <= n; i++) {
		if(s[i] != '?') {
			int c = s[i] - 'a' + 1;
			a[i][0] = (1 << c);
		}
	}
	for(int i = 2; i <= n; i++) lg[i] = lg[i >> 1] + 1;
	for(int j = 1; j <= 18; j++) {
		for(int i = 1; i + (1 << j) - 1 <= n; i++) {
			a[i][j] = a[i][j - 1] | a[i + (1 << (j - 1))][j - 1];
		}
	}

	int l = 0, r = n;
	while(l <= r) {
		int mid = (l + r) >> 1;
		if(check(mid)) l = mid + 1, ans = mid;
		else r = mid - 1;
	}

	std::cout << ans << "\n";
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
	solve();

	return 0;
}
posted @ 2024-06-06 21:50  Fire_Raku  阅读(5)  评论(0编辑  收藏  举报