P10360 [PA2024] Desant 3
什么构史玩意。
首先你会一个 \(O(2^n(m+\operatorname{poly}(n)))\) 的暴力。状态数有足足 \(2^{35}\) 这么多,过不了。然后就不会了。
答案是模 \(2\) 输出,这启示我们很多状态对答案其实都没有影响,于是仍然搜索,记录每个位置是不填不确定或者已经填数,考虑第 \(x\) 个操作 \((a_x,b_x)\) 的贡献:
1.操作的两个位置都已确定,直接模拟即可。不会增加状态数。
2.一个位置不确定,若 \(a_x\) 位置上为 \(1\) 或 \(b_x\) 上为 \(0\) 即交换两个位置。这是因为如果另一个位置填的数不同那么一定交换,如果相同那么换不换都无所谓。状态数不改变。
3.两个位置都不确定。枚举这两个位置上的 \(4\) 种情况。发现 \((0,1),(1,0)\) 这一步后一定相同,也即对答案没有贡献。故只有 \((0,0),(1,1)\) 有用,继续搜索即可。
发现状态数的增加只来源于第三种情况。每次确定两个位置,同时状态数翻倍,总状态数是 \(2^\frac{n}{2}\)。于是总复杂度 \(O(2^\frac{n}{2}(m+\operatorname{poly}(n)))\)。
#include<iostream>
#include<algorithm>
int n, m, a[1005], b[1005], f[40], rs[40];
void dfs(int x){
if(x > m){
int ct = std::count(f + 1, f + n + 1, 1);
for(int i = 1, sm = 0; i <= n; i++, sm = 0)
for(int j = i; j <= n; j++){
if(f[j] == 0) break;
if(f[j] == 1) ++sm;
if(sm == ct) rs[j - i + 1] ^= 1;
}
} else if(f[a[x]] >= 0 && f[b[x]] >= 0){
int fl = (f[a[x]] == 1 && f[b[x]] == 0);
if(fl) std::swap(f[a[x]], f[b[x]]);
dfs(x + 1); if(fl) std::swap(f[a[x]], f[b[x]]);
} else if(f[a[x]] < 0 && f[b[x]] < 0){
f[a[x]] = f[b[x]] = 0, dfs(x + 1);
f[a[x]] = f[b[x]] = 1, dfs(x + 1);
f[a[x]] = f[b[x]] = -1;
} else {
int fl = 0; if(f[a[x]] >= 0)
fl = f[a[x]] == 1 && (std::swap(f[a[x]], f[b[x]]),1);
else fl = f[b[x]] == 0 && (std::swap(f[a[x]], f[b[x]]),1);
dfs(x + 1); if(fl) std::swap(f[a[x]], f[b[x]]);
} return;
}
int main(){
std::cin >> n >> m; std::fill(f + 1, f + n + 1, -1);
for(int i = 1; i <= m; i++) std::cin >> a[i] >> b[i];
dfs(1); for(int i = 1; i <= n; i++) std::cout << rs[i] << ' ';
}