N*M的方格,每个位置有一枚朝上或朝下的硬币,两人轮流操作,每次操作可以选择矩形的四个顶点,把四个点位置的硬币翻转,要求右下角位置的硬币必须是从正到反,求先手胜负。2009年国家集训队论文 曹钦翔《从“k倍动态减法游戏”出发探究一类组合游戏问题》里的例题,里面提出了NIM积并给出了求NIM积的方法,具体讲解参见论文,实在看不懂的就先把结论给记下来吧....
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn=2002000;
int m[2][2]={0,0,0,1};
int NimMultiPower(int x,int y)
{
if (x<2) return m[x][y];
int a=0;
for (;; a++)
if (x>=(1<<(1<<a)) && x<(1<<(1<<(a+1)))) break;
int m=1<<(1<<a);
int p=x/m,s=y/m,t=y%m;
int d1=NimMultiPower(p,s);
int d2=NimMultiPower(p,t);
return (m*(d1^d2))^NimMultiPower(m/2,d1);
}
int NimMulti(int x,int y)
{
if (x<y) return NimMulti(y,x);
if (x<2) return m[x][y];
int a=0;
for (;; a++)
{
if (x>=(1<<(1<<a)) && x<(1<<(1<<(a+1)))) break;
}
int m=(1<<(1<<a));
int p=x/m,q=x%m,s=y/m,t=y%m;
int c1=NimMulti(p,s),c2=NimMulti(p,t)^NimMulti(q,s),c3=NimMulti(q,t);
return (m*(c1^c2))^c3^NimMultiPower(m/2,c1);
}
int n,tt;
int main()
{
int x,y;
scanf("%d",&tt);
while(tt--)
{
scanf("%d",&n);
int ans=0;
for (int i=1; i<=n; i++)
{
scanf("%d%d",&x,&y);
ans^=NimMulti(x,y);
}
if (ans) puts("Have a try, lxhgww.");
else puts("Don't waste your time.");
}
return 0;
}