ACM学习历程—HDU 3915 Game(Nim博弈 && xor高斯消元)

本文介绍了一道ACM竞赛题目的解法,该题目涉及Nim博弈和XOR高斯消元算法。通过对给定的堆进行处理,使用XOR高斯消元找出能够构成必败局势的所有取法数量。

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3915

题目大意是给了n个堆,然后去掉一些堆,使得先手变成必败局势。

首先这是个Nim博弈,必败局势是所有xor和为0.

那么自然变成了n个数里面取出一些数,使得xor和为0,求取法数。

首先由xor高斯消元得到一组向量基,但是这些向量基是无法表示0的。

所以要表示0,必须有若干0来表示,所以n-row就是消元结束后0的个数,那么2^(n-row)就是能组成0的种数。

n==row特判一下。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <map>
#include <queue>
#include <string>
#define LL long long

using namespace std;

const int maxN = 105;
const int MOD = 1000007;
int n, s[maxN];

void input()
{
    scanf("%d", &n);
    for (int i = 0; i < n; ++i)
        scanf("%d", &s[i]);
}

//xor高斯消元求线性基
//时间复杂度O(30n)
int xorGauss(int n)
{
    int row = 0;
    for (int i = 30; i >= 0; i--)
    {
        int j;
        for (j = row; j < n; j++)
            if(s[j]&(1<<i))
                break;
        if (j != n)
        {
            swap(s[row], s[j]);
            for (j = 0; j < n; j++)
            {
                if(j == row) continue;
                if(s[j]&(1<<i))
                    s[j] ^= s[row];
            }
            row++;
        }
    }
    return row;
}

void work()
{
    int row, ans, k;
    row = xorGauss(n);
    ans = n-row;
    if (ans != -1)
    {
        k = 1;
        while (ans)
        {
            k <<= 1;
            k %= MOD;
            ans--;
        }
        ans = k;
    }
    else
        ans = -1;
    printf("%d\n", ans);
}

int main()
{
    //freopen("test.in", "r", stdin);
    int T;
    scanf("%d", &T);
    for (int times = 0; times < T; ++times)
    {
        input();
        work();
    }
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/andyqsmart/p/4970095.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值