HDU 3404 Switch light (Nim积)

题面:

lxhgww is playing a game with his computer Deep Blue. The game is played on a matrix containing lights. At first, some lights are on, while others are off. lxhgww and Deep Blue take turns to switch the lights. For each step, the player should choose a rectangle in the matrix: (x1, y1) , (x1, y2) , (x2, y1) , (x2, y2) , (x1 <= x2, y1 <= y2, the light at (x2, y2) should be on) and change the lights’ status on the four vertex of the rectangle, namely on to off, and off to on. The player turns all the lights off wins the game. Notice the rectangle is possibly degenerated to line or even a single cell so that the player may also switch two or one besides four lights in a move. Deep Blue’s strategy is perfect, if it has a chance to win, never will it lose. Does lxhgww have a chance to win if he takes the first step?

Input

The first line is an integer T(T<=100) indicating the case number.
Each case has one integers n (n<= 1000 ), the number of on-lights at the beginning of the game.
Then come n lines, each line has two integers, xi , yi, (1<=xi<=10000, 1<=yi<=10000) , so light at (xi, yi) is on at first. (No two lights at the same position)

Output

If lxhgww still has a chance to win, output “Have a try, lxhgww.”, otherwise tell lxhgww “Don’t waste your time.”

Sample Input

2
2
1 2
2 1
2
1 1
2 2

Sample Output

Don’t waste your time.
Have a try, lxhgww.

解:

这是一道Nim积的模板题,可是查了好多东西只有一篇论文比较详细讲了Nim积,可惜的是看到一半就懵了。
论文:http://www.doc88.com/p-5098170314707.html

#include <cstdio>
#include <cmath>
#include <iostream>
#include <cstring>
using namespace std;

typedef long long ll;
const int N  = 1e4+10;

int sg[20][20];

int nimmul(int x, int y);

int nimpow(int x, int y)//计算2^x和2^y的nim积
{
    if(sg[x][y] != -1)
        return sg[x][y];
    if(!x)//1与2^y的nim积
        return sg[x][y] = 1 << y;
    if(!y)//1与2^x的nim积
        return sg[x][y] = 1 << x;
    int ans = 1, k = 1, x1 = x, y1 = y, t;
    while(x || y)//将x和y分解为二进制,计算普通乘积的,即对应二进制位不同的
    {
        t = 1 << k;
        if((x & 1 || y & 1) && !((x & 1) && (y & 1)))//该位不同
            ans *= t;
        x >>= 1;
        y >>= 1;
        k <<= 1;//从此位得到指数(指数也是2的幂)
    }
    k = 1;
    x = x1;
    y = y1;
    while(x || y)//计算相同的费马数,与已得出的数的nim积
    {
        t = 1 << k;
        if((x & 1) && (y & 1))//该位相同
            ans = nimmul(ans, t/2*3);
        x >>= 1;
        y >>= 1;
        k <<= 1;//从此位得到指数(指数也是2的幂)
    }
    return (sg[x1][y1] = ans);
}

int nimmul(int x, int y)
{
    if(!x || !y)
        return 0;
    if(x == 1)
        return y;
    if(y == 1)
        return x;
    int ans = 0;
    for(int i = x, a = 0; i; i >>= 1, a++)//将x和y分解后按分配律计算积
    {
        if((i & 1) == 0)//该二进制位是1才计算,否则跳过
            continue;
        for(int j = y, b = 0; j; j >>= 1, b++)
        {
            if((j & 1) == 0)
                continue;
            ans ^= nimpow(a, b);
        }
    }
    return ans;
}

int main()
{
    int t;
    cin >> t;
    while(t--)
    {
        memset(sg, -1, sizeof(sg));
        int n;
        cin >> n;
        int x, y, ans = 0;
        for(int i = 0; i < n; ++i)
        {
            scanf("%d%d", &x, &y);
            ans ^= nimmul(x, y);
        }
        if(ans)
            printf("Have a try, lxhgww.\n");
        else
            printf("Don't waste your time.\n");
    }
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值