小志志和小峰峰的日常
Time Limit: 1000 ms Memory Limit: 65536 KiB
Problem Description
小志志和小峰峰特别喜欢一起讨论一些很好玩的问题。
小志志发现一个有趣的游戏,马上和小峰峰进行了分享。
有 n 堆石子堆,每堆石子个数为 a[i]。
到小志志的回合:小志志可以选取其中的一堆,拿至少 1 个最多 x 个石子。
到小峰峰的回合:小峰峰可以选取其中的一堆,拿至少 1 个最多 y 个石子。
小志志先手,回合交替进行,到该玩家回合如果无法操作,该玩家输。
Input
输入一个 T,总共有 T 组测试数据。
每组测试数据:
第一行输入 n 代表有 n 堆石子堆。
第二行输入 n 堆石子堆分别的数量。
第三行输入两个用空格隔开的 x, y 分别代表小志志和小峰峰对于一堆石子最多能拿的数量。
(1 <= n <= 1e5, 1 <= a[i], x, y <= 1e9)
Output
小志志赢输出 “xzz”,小峰峰赢输出 “xff”,答案不包含 “”。
Sample Input
3 1 3 2 2 2 4 7 4 5 3 3 4 7 8 8
Sample Output
xff xzz xff
题解:
我们需要分类讨论:
x == y 的时候:经典的 sg
x != y 的时候:
任意的 a[i] <= min(x, y):Nim 博弈
否则至少存在一堆 a[i] > min(x, y):
如果 x > y:
我们把先手能拿的石子个数看成 y 的话,就是经典的 sg,如果亦或和不是 0 那么先手必
胜。
如果亦或和是 0,那么先手可以选择石子个数大于 y 的堆,拿掉 y+1 的石子个数。这样对
于对方而言亦或和还是 0。所以先手必胜。
所以无论如何:先手必胜
如果 x < y:
如果石子堆个数 > min(x, y) 的堆数大于 2:后手必胜,先手无论如何处理都会变成上述的
情况。
如果石子堆个数 > min(x, y) 的堆数 == 1:
先手肯定会选择 > min(x, y) 的石子堆进行操作,不然先手必败。
设这堆石子个数为 t,除去这堆石子的亦或和为 ans,你只有将这堆石子个数变成 ans &&
ans <= x 才能赢。
所以 t-x <= ans && ans <= x 先手必胜。
否则先手必败。
#include<bits/stdc++.h> #define ll long long using namespace std; const int N = 1e5+5; string s[2]; ll n, x, y, T; ll arr[N]; bool f1(ll ans){ for(int i = 1; i <= n; i++) ans ^= arr[i]%(x+1); return ans != 0; } int main() { s[1] = "xzz", s[0] = "xff"; cin >> T; while(T--) { cin >> n; for(int i = 1; i <= n; i++) cin >> arr[i]; cin >> x >> y; if(x == y) cout << s[f1(0)] << endl; //经典sg else{ int flag = 0, ans = 0; for(int i = 1; i <= n; i++){ ans ^= arr[i]; if(arr[i] > min(x, y)) flag++; } if(!flag){ // Nim博弈 if(ans) cout << s[1] << endl; else cout << s[0] << endl; } else{ if(x > y) cout << s[1] << endl; else{ if(flag > 1) cout << s[0] << endl; else{ int t; for(int i = 1; i <= n; i++){ if(arr[i] > min(x, y)){ t = arr[i]; ans ^= arr[i]; break; } } if(t - ans <= x && ans <= x) cout << s[1] << endl; else cout << s[0] << endl; } } } } } return 0; }
原文地址:https://www.cnblogs.com/philo-zhou/p/11391233.html