专栏文章

题解:CF76C Mutation

CF76C题解参与者 2已保存评论 1

文章操作

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

当前评论
1 条
当前快照
1 份
快照标识符
@miq7vtpu
此快照首次捕获于
2025/12/04 00:24
3 个月前
此快照最后确认于
2025/12/04 00:24
3 个月前
查看原文
本蒟蒻第一次写紫题题解,大佬轻喷。

题目大意:

题目写的很直白明了,这里不写了。

思路:

我们即询问有多少种删除的字符集是合法的,只需要对于每种删除的字符集计算出相邻字符产生的代价即可。
考虑对于两个位置 (i,j)(i,j),其能产生代价当旦仅当中间的字符被删光且 i,ji,j 都没被删,考虑中间的字符集为 TT,那么产生贡献的即为所有 TT 的不包含 si,sjs_i,s_j 的超集 SS
首先显然要有 TT 不包含 si,sjs_i,s_j。于是乎我们发现,如果我们钦定了 ii,再枚举一个字符 CC,那么 ii 右侧第一个字符 cc 才有可能产生贡献,那么有贡献的 (i,j)(i,j) 就只有 O(nk)O(nk) 对。
考虑对于一组 (S,a,b)(S,a,b) 产生的贡献,其中 a,ba,b 表示 si,sjs_i,s_j,即为不可删的字符。我们只需要对 fs,fsa,bf_s,f_{s\cup a,b} 进行一个 +ma,b+m_{a,b} 的贡献,fs{a},fs{b}f_{s\cup \{a\}},f_{s\cup \{b\}},进行一个 ma,b-m_{a,b} 的贡献即可。
然后我们对 ff 进行高维前缀和即可得到代价数组 gg
这样的话时间复杂度为 O(nk+2kk)O(n\cdot k+2^k\cdot k)

代码:

CPP
#include<bits/stdc++.h>

using namespace std;
const int N = 2e5 + 10, K = 25;
int n, k, T, sum, b[K], t[K], a[K][K], f[1 << K], ans;
string s;

void init() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cin >> n >> k >> T >> s;
	for (int i = 0; i < n; i++) {
		s[i] -= 'A';
	}
	for (int i = 0; i < n; i++) {
		sum |= 1 << s[i];
	}
	for (int i = 0; i < k; i++) {
		cin >> t[i];
	}
	for (int i = 0; i < k; i++) {
		for (int j = 0; j < k; j++) {
			cin >> a[i][j];
		}
	}
	return ;
}

int main() {
	init();
	memset(b, -1, sizeof b);
	for (int i = 0; i < k; i++) {
		f[1 << i] = t[i];
	}
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < k; j++) {
			if (b[j] >= 0) {
				if (!((b[j] >> j) & 1) && !((b[j] >> s[i]) & 1)) {
					f[b[j]] += a[j][s[i]];
					f[b[j] | (1 << j)] -= a[j][s[i]];
					f[b[j] | (1 << s[i])] -= a[j][s[i]];
					f[b[j] | (1 << j) | (1 << s[i])] += a[j][s[i]];
				}
				b[j] |= (1 << s[i]);
			}
		}
		b[s[i]] = 0;
	}
	for (int i = 0; i < k; i++) {
		for (int j = 0; j < 1 << k; j++) {
			if ((j >> i) & 1) {
				f[j] += f[j ^ (1 << i)];
			}
		}
	}
	for (int i = 0; i < 1 << k; i++) {
		if ((i & sum) == i && f[i] <= T && i != sum) {
			ans++;
		}
	}
	cout << ans;
	return 0;
}

评论

1 条评论,欢迎与作者交流。

正在加载评论...