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] << ' ';
}
posted @ 2024-07-24 21:28  xlpg0713  阅读(1)  评论(0编辑  收藏  举报