题解:CF1975F Set
神仙题,看了好久题解才看懂,那就来写一篇比较详细的题解并给出一个较为简洁的实现吧 qwq
我们记 &。
题目里面
观察
我们考虑把
分讨
- 若有,则第二个条件变为
\lvert S\cap f^{-1}(t)\rvert+1\in f^{-1}(v_{t+2^{n-1}}) ,即\lvert S\cap f^{-1}(t)\rvert\in f^{-1}(\lfloor\frac{v_{t+2^{n-1}}}{2}\rfloor) 。联立第一个条件得到\lvert S\cap f^{-1}(t)\rvert\in f^{-1}(v_t)\cap f^{-1}(\lfloor\frac{v_{t+2^{n-1}}}{2}\rfloor) ,也就是:\forall t\in[0,2^{n-1}),\lvert S\cap f^{-1}(t)\rvert\in f^{-1}(v_t\land \lfloor\frac{v_{t+2^{n-1}}}{2}\rfloor) - 若没有,第二个条件变为
\lvert S\cap f^{-1}(t)\rvert\in f^{-1}(v_{t+2^{n-1}}) ,联立第一个条件得\forall t\in[0,2^{n-1}),\lvert S\cap f^{-1}(t)\rvert\in f^{-1}(v_t\land v_{t+2^{n-1}})
对照最前面
至于实现,我们可以不真地递归下去,而是从
时间复杂度
参考代码:
... // 下文 REP(i, l, r) 表示从 l 到 r 枚举 i
namespace Milkcat {
typedef long long LL;
typedef pair<LL, LL> pii;
const int N = 2e6 + 5;
int n, ct, v[N];
int main() {
cin >> n, v[0] = 1; // 去除 T 不为空的限制
REP(i, 1, (1 << n) - 1) cin >> v[i];
for (int k = 1 << (n - 1); k; k >>= 1) // 长度为 2k 的区间分成前后长度为 k 的两半
REP(i, 0, (1 << n) - 1) {
if (i & k) continue; // 是否在区间中的前一半,若在后一半则跳过
int x = v[i], y = v[i + k];
v[i] = x & y, v[i + k] = x & y >> 1; // 同时处理前后两半中对应的数
}
REP(i, 0, (1 << n) - 1) ct += v[i] & 1;
cout << ct << '\n';
REP(i, 0, (1 << n) - 1)
if (v[i] & 1) cout << i << '\n';
return 0;
}
}