A Bit Odd
A Bit Odd
问题描述
给定长度为 n 的二进制字符串 s(只含 0 和 1)。
Alice 和 Bob 轮流操作,Alice 先手。
每次操作必须选择一个 子序列,该子序列的 逆序对数量为奇数,然后删除它。
无法操作的玩家输。
判断在最优策略下谁获胜。
前置知识
- 逆序对:在二进制串中,若
i < j且s[i] = '1'、s[j] = '0',则(i, j)为一个逆序对。 - 子序列:从原串中删除若干(可能零个或全部)字符后得到的序列。
核心观察
1. 全 0 或全 1 的串是必败态
- 没有任何逆序对,当前玩家无法操作,直接输。
2. 先手能否一步清空整个串?
情况 A:删除所有 1
- 取所有
1作为子序列(可以带任意0)。 - 逆序对总数 = 每个被选中的
0前面被选中的1的个数之和。 - 存在某个
0前方有奇数个1⇔ 可以构造奇数逆序对子序列,从而一次删完所有1,直接获胜。
情况 B:删除所有 0
- 对称地,存在某个
1后方有奇数个0⇔ 可以一次删完所有0,直接获胜。
若上述任一条件成立,Alice 第一步即可获胜。
必败态的结构
若上述两个条件均不成立,则字符串必为以下形式:
0 (XX) (XX) ... (XX) 1
其中每一对 (XX) 要么是 "00",要么是 "11"。
开头的 0 和结尾的 1 是可选的(可能不存在)。
特点:
- 每个
0前的1的个数都是偶数; - 每个
1后的0的个数都是偶数; - 总逆序对数为偶数,且任何合法操作都会把胜利交给对手,因此这种状态是 必败态。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void solve() {
int n; cin >> n; string s; cin >> s;
int k1 = 0, k0 = 0;
bool flag = false;
for(int i = 0; i < n; i ++) {
if(s[i] == '1') k1 ++;
else {
if(k1 & 1) flag = true;
}
}
for(int i = n - 1; i >= 0; i --) {
if(s[i] == '0') k0 ++;
else {
if(k0 & 1) flag = true;
}
}
cout << (flag ? "Alice" : "Bob") << "\n";
}
int main() {
ios::sync_with_stdio(false); cin.tie(nullptr);
int t = 1; cin >> t;
while(t --) solve();
return 0;
}

浙公网安备 33010602011771号