P1247 取火柴游戏(nim游戏+取第一个数判断)
题目描述:
思路:nim游戏,判断能不能先手赢就是直接把所有值异或,为0说明无论如何取,另一个人都能找到一个与之相同数目的火柴堆,无法胜利/必输。
那么第一步取那个呢?
假设x是1-n所有数目的异或和,那么我们只需要将x再^x就是0了,轮到下一个人就必输,如何实现呢?
我们只需要找到一个满足x^a[i]<=a[i]的位置,然后把该位置的值变为a[i]^x,相当于进行了一次a[i]^x的操作,这样总体看来就相当于进行了一次x^x
的操作,即剩下的就满足先手必输了,即所有值异或和为0,而该位置取得数目就是a[i]-(a[i]^x)。
AC代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 10000005; const int inf = 0x3f3f3f3f; int n; int a[maxn]; int main() { scanf("%d", &n); int ans = 0; for (int i = 1; i <= n; i++) { scanf("%d", a + i); ans ^= a[i]; } if (ans == 0) {//无法获胜 printf("lose\n"); return 0; } for (int i = 1; i <= n; i++) { if ((ans^a[i])<a[i]) { //ans^a[i] a[i]改为ans^a[i] printf("%d %d\n", a[i] - (a[i] ^ ans), i); a[i] = ans ^ a[i]; for (int i = 1; i <= n; i++) { printf("%d", a[i]); if (i != n)printf(" "); } return 0; } } return 0; }