限制问题
问题描述
有 \(n(n \le 20)\) 个数 \(0 \sim n - 1\),现在要选出若干个数。
给定 \(m \le 2 \times 10^5\) 条限制,每条限制给定集合 \(S \subseteq \{0, 1, 2, \dots n - 1\}\),要求选出的数中至少有一个 \(x \in S\)。问至少需要选出几个数。
解决方式
令全集 \(U = \{0, 1, 2, \dots, n - 1 \}\)。
考虑每种选取方式。对于每条限制,直接做比较复杂,考虑反面:令 \(P = \complement_U S\),那么所有 \(P\) 的子集都不满足要求。在 \(P\) 位置打个标记,最后做高维前缀和即可。
时间复杂度:\(O(nm + n2^n)\)。
#include <bits/stdc++.h>
using namespace std;
const int MAXU = (1 << 20);
int n, m, f[MAXU];
int main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> m;
int U = (1 << n) - 1; //全集
for (int i = 1, k; i <= m; i++) {
cin >> k;
int u = 0;
for (int x; k--; ) {
cin >> x, u ^= (1 << x);
}
f[U ^ u]++; // 打标记
}
for (int i = 0; i < n; i++) { // 高维前缀和
for (int j = U; j >= 0; j--) {
if (((j >> i) & 1) ^ 1) {
f[j] += f[j ^ (1 << i)];
}
}
}
int ans = n;
for (int i = 0; i <= U; i++) {
if (f[i]) continue;
int c = 0;
for (int x = 0; x < n; x++) {
c += ((i >> x) & 1);
}
ans = min(ans, c);
}
cout << ans;
return 0;
}
现在你应该已经会了吧,来试试 CF1995D。
浙公网安备 33010602011771号