题解:CF2241F A Bit Odd

· · 题解

显然若剩余序列长度 \le1,则个序列的逆序对数为 0,当前玩家必败。接下来考虑以下三种状态:

:::info[证明] 定义 \operatorname{inv}(s) 表示字符串 s 的逆序对数。假设初始时处于状态三,Alice 选择删除子序列 a,且剩下了子序列 b。由于 s 处于状态三,s 中任何一个 0 前面都有偶数个 1,任何一个 1 后面都有偶数个 0;并且根据题目要求,必须有 \operatorname{inv}(a)\equiv1\pmod2。我们需要证明子序列 b 不可能处于状态三。

\operatorname{inv}(a,b) 表示 a,b 之间的交叉逆序对数量。交叉逆序对分为两种:

s 拆分为 ab 时,总逆序对数满足 \operatorname{inv}(s)=\operatorname{inv}(a)+\operatorname{inv}(b)+\operatorname{inv}(a,b)

我们使用反证法,先假设 b 也处于状态三。考察 \operatorname{inv}(a,b) 的奇偶性:

既然两种类型的交叉逆序对数量都是偶数,那么二者之和,即 \operatorname{inv}(a,b) 也是偶数。

将这些奇偶性代入之前的式子:

\operatorname{inv}(s)&=\operatorname{inv}(a)+\operatorname{inv}(b)+\operatorname{inv}(a,b)\\ 0&\equiv1+\operatorname{inv}(b)+0\pmod2\\ \operatorname{inv}(b)&\equiv1\pmod2 \end{aligned}

这说明 \operatorname{inv}(b) 一定是奇数,也就是 b 处于状态一,与假设矛盾,故子序列 b 不可能处于状态三,即 Alice 操作后剩下的序列一定是状态一或状态二,所以初始时若 s 处于状态三,则 Bob 必胜。 :::

由于是 01 串,维护逆序对数只需要前缀和,不需要树状数组之类的。

Submission & Code:

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 200005;
int _, n, sum[N], tot;
string s;
bool flag;
signed main() {
    cin >> _;
    while (_--) {
        cin >> n >> s;
        s = " " + s;
        for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + (s[i] ^ 48);
        tot = 0;
        for (int i = 1; i <= n; i++) if (s[i] == '0') tot += sum[i];
        if (tot & 1) {
            puts("Alice");
            continue;
        }
        flag = 0;
        for (int i = 1; i <= n; i++) {
            if (s[i] == '0' && (sum[i] & 1)) {
                flag = 1;
                break;
            } else if (s[i] == '1' && ((n - i - sum[n] + sum[i]) & 1)) {
                flag = 1;
                break;
            }
        }
        puts(flag ? "Alice" : "Bob");
    }
    return 0;
}