先介绍一下Nim博弈
如果这堆石头数量异或和为0,先手必败,否则先手必胜
这边给出证明:
一个人最终会输,也就是说他需要面对没有石头的那种情况,这边给两个概念:
一个人面对石头数量异或和为0的时候,这个人处于必败态
一个人面对石头数量异或和不为0的时候,这个人处于必胜态
这个人处于必败态的时候,下一步无论取走多少石头都能让异或和变得不等于0,这个时候对手就处于必胜态
这个人处于必胜态的时候,我们要取走一些石头让异或和为0,我们去找有异或和 S 二进制最高位的那一堆石头(因为最高位是1,石头堆里面肯定有一个有异或和最高位的那一堆石头),记为arr[i],除了arr[i]之外的石头数量异或和为S ^ arr[i],我们在这一堆石头中拿走arr[i] - (arr[i] ^ S)个石头,此时异或和变为S ^ arr[i] ^ (arr[i] - (arr[i] - (arr[i] ^ S))) = S ^ arr[i] ^ (arr[i] ^ S) = 0,这个时候就能让对手处于必败态
差不多就是这个样子
最终的必败态也就是0了,证明结束
//
对于这题来说,小A如果一开始面对的异或和不为0的话,那他游戏开始前不取就行了,这样他肯定能赢
如果他面对的异或和是0的话,这里他肯定要取走k个石头让总异或和不为0,那只需要考虑一下能不能取走k个(也就是最大值需要大于等于k)和取走之后异或和会不会变(也就是k等不等于0)
这边贴代码
#include <bits/stdc++.h>
using namespace std;
void solve() {
// nim博弈
int n,k;
cin >> n >> k;
vector<int> arr(n);
for (auto& v : arr)cin >> v;
int xorsum = 0;
for (auto& v : arr){
xorsum ^= v;
}
if(xorsum == 0){
int maxv = *max_element(arr.begin(),arr.end());
if (maxv < k || k == 0) {
cout << "NO\n";
return;
}
cout << "YES\n";
}
else{
cout << "YES\n";
}
}
int main() {
ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
solve();
return 0;
}

京公网安备 11010502036488号