标签:
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3915
题目大意是给了n个堆,然后去掉一些堆,使得先手变成必败局势。
首先这是个Nim博弈,必败局势是所有xor和为0.
那么自然变成了n个数里面取出一些数,使得xor和为0,求取法数。
首先由xor高斯消元得到一组向量基,但是这些向量基是无法表示0的。
所以要表示0,必须有若干0来表示,所以n-row就是消元结束后0的个数,那么2^(n-row)就是能组成0的种数。
对n==row特判一下。
代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <algorithm> #include <set> #include <map> #include <queue> #include <string> #define LL long long using namespace std; const int maxN = 105; const int MOD = 1000007; int n, s[maxN]; void input() { scanf("%d", &n); for (int i = 0; i < n; ++i) scanf("%d", &s[i]); } //xor高斯消元求线性基 //时间复杂度O(30n) int xorGauss(int n) { int row = 0; for (int i = 30; i >= 0; i--) { int j; for (j = row; j < n; j++) if(s[j]&(1<<i)) break; if (j != n) { swap(s[row], s[j]); for (j = 0; j < n; j++) { if(j == row) continue; if(s[j]&(1<<i)) s[j] ^= s[row]; } row++; } } return row; } void work() { int row, ans, k; row = xorGauss(n); ans = n-row; if (ans != -1) { k = 1; while (ans) { k <<= 1; k %= MOD; ans--; } ans = k; } else ans = -1; printf("%d\n", ans); } int main() { //freopen("test.in", "r", stdin); int T; scanf("%d", &T); for (int times = 0; times < T; ++times) { input(); work(); } return 0; }
ACM学习历程—HDU 3915 Game(Nim博弈 && xor高斯消元)
标签:
原文地址:http://www.cnblogs.com/andyqsmart/p/4970095.html