hdu3404 Switch lights 求NIM积

   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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值