题目链接:
题意:两个人玩游戏,有 n 块石头,初始坐标为(x,y),一次操作可以将一块石头移动到(x - u,y),(x,y - u)或者(x - u,y - u),坐标为(0,0)的石子不能移动,问先手赢还是输。
题解:显然移动石子不能移动到 x = 0,y = 0 或者 x = y 的直线上,否则下一个玩家通过一步就可以获胜,故求 sg 值的时候,遇到这些坐标上的点直接跳过,答案则为全部石子异或和,特批一下一开始是否有在 x = y 直线上的石子即可。
1 #include2 #define sd(a) scanf("%d",&a) 3 #define sld(a) scanf("%lld",&a) 4 #define mst(a,b) memset(a,b,sizeof a) 5 #define pb push_back 6 #define mp make_pair 7 typedef long long ll; 8 using namespace std; 9 typedef pair pii;10 const int maxn = 1e3 + 10;11 int inf = 0x3f3f3f3f;12 13 bool vis[210];14 int sg[110][110];15 16 void getsg() {17 mst(sg, 0);18 for(int i = 1; i <= 100; i++) {19 for(int j = 1; j <= 100; j++) {20 if(i == j) continue;21 mst(vis, false);22 int mx = max(i, j);23 for(int k = 1; k <= mx; k++) {24 if(i > k && (i - k) != j) vis[sg[i - k][j]] = true;25 if(j > k && (j - k) != i) vis[sg[i][j - k]] = true;26 if(i > k && j > k) vis[sg[i - k][j - k]] = true;27 }28 for(int k = 0; ; k++) {29 if(!vis[k]) {30 sg[i][j] = k;31 break;32 }33 }34 }35 }36 }37 38 int main() {39 #ifdef local40 freopen("data.txt","r",stdin);41 #endif // local42 // init();43 getsg();44 int n;45 scanf("%d",&n);46 int flag = 0;47 int ans = 0;48 for(int i = 0; i < n; i++) {49 int x,y;50 scanf("%d%d",&x,&y);51 if(x == y) flag = 1;52 ans ^= sg[x][y];53 }54 if(flag || ans) puts("Y");55 else puts("N");56 return 0;57 }