题解:CF2241F A Bit Odd
显然若剩余序列长度
- 若初始时逆序对数为奇数,则 Alice 可以直接把整个序列扔掉,剩下一个空序列,Alice 必胜。
- 若初始时逆序对数为偶数,且存在一个下标
i 使得s 去掉s_i 后逆序对数为奇数(等价于s_i 贡献的逆序对数为奇数),则 Alice 可以直接把除了s_i 之外的整个序列扔掉,剩下一个长度为1 的序列,Alice 必胜。 - 如果以上两种情况都不满足,我们发挥自己的注意力,猜测此时 Bob 必胜。
:::info[证明]
定义
记
将
我们使用反证法,先假设
- 对于第一种类型的交叉逆序对,考虑
b 中每个0 :原序列s 中它前面有偶数个1 ;而在b 中,由于b 也处于状态三,故在b 中它前面也有偶数个1 。由于两偶数相减得到的仍然为偶数,故在a 中且在它前面的1 的数量也为偶数。将b 中所有0 贡献的偶数个交叉逆序对求和,得到的仍然是偶数。 - 对于第二种类型的交叉逆序对,考虑
b 中每个1 :原序列s 中它后面有偶数个0 ;而在b 中,由于b 也处于状态三,故在b 中它后面也有偶数个0 。由于两偶数相减得到的仍然为偶数,故在a 中且在它后面的0 的数量也为偶数。将b 中所有1 贡献的偶数个交叉逆序对求和,得到的仍然是偶数。
既然两种类型的交叉逆序对数量都是偶数,那么二者之和,即
将这些奇偶性代入之前的式子:
这说明
由于是
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;
}