bzoj4600 [Sdoi2016]硬币游戏
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4600
【题解】
显然可以发现对于每个c,互相独立。
博弈问题,考虑sg函数。
预处理出每个数的2的因数个数t2[i],3的因数个数t3[i]
对于这一次能翻的硬币,记忆化搞搞sg值,然后异或起来即可。
sg函数非常神奇啊qwq
这题你进去会发现 一个状态的后继状态是由好几个硬币构成的,那么把他们异或起来就行了!
# include <stdio.h> # include <string.h> # include <algorithm> // # include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int M = 3e4 + 10, N = 20; const int mod = 1e9+7; # define RG register # define ST static int n, m, t2[M], t3[M]; int sg[N][N]; bool vis[N][N]; inline int getsg(int x, int y) { if(vis[x][y]) return sg[x][y]; vis[x][y] = 1; int SG; bool g[62]; memset(g, 0, sizeof g); for (int q=1; q<=m; ++q) { for (int p=1; p*q<=x; ++p) { int s = 0; bool hv = 0; for (int j=0; j<=q; ++j) { if(!hv) hv = 1; s = s ^ getsg(x-p*j, y); } if(hv) g[s] = 1; } } for (int q=1; q<=m; ++q) { for (int p=1; p*q<=y; ++p) { int s = 0; bool hv = 0; for (int j=0; j<=q; ++j) { if(!hv) hv = 1; s = s ^ getsg(x, y-p*j); } if(hv) g[s] = 1; } } for (int i=0; i<=60; ++i) if(!g[i]) { SG = i; break; } return sg[x][y] = SG; } inline void sol() { memset(vis, 0, sizeof vis); memset(sg, 0, sizeof sg); scanf("%d%d", &n, &m); int ans = 0; for (int i=1, t; i<=n; ++i) { scanf("%d", &t); if(t) continue; ans ^= getsg(t2[i], t3[i]); } if(ans) puts("win"); else puts("lose"); } int main() { for (int i=1; i<=30000; ++i) { int t = i; while(t%2 == 0) t2[i] ++, t/=2; while(t%3 == 0) t3[i] ++, t/=3; } int T; scanf("%d", &T); while(T--) sol(); return 0; }