BZOJ 1299 [LLH邀请赛]巧克力棒 博弈(NIM游戏)+构造

题意:链接

方法:博弈+构造

解析:

神题没想到咋做,看完wyf大爷说的话才懂

这道题的题意就是有n堆石子,之后你每次操作有两种做法

第一种是在已经建立的nim游戏上进行nim游戏。

第二种是在未被选的堆中选取若干堆加入这个nim游戏中。

所以这怎么做?

我一直尝试去建立一个必败态,不过可能我走的方法过多的考虑了将这道题转变为nim游戏套nim游戏而最终走入死胡同,不会做了。

然而这道题的必败态可以这么建:如果是先手的话,我可以建立出来一个异或和为0的nim游戏,此时后者有两种做法,第一种是在该nim游戏上游戏,则先手又可以将这个游戏的异或和变为0,第二种是选取新的石子堆加入原来的nim游戏,如果是先手的话不会给后手机会来添加一组异或和为0的石子堆。所以先手建立的一定是选取最多的元素的异或和为0的nim游戏,此时,在剩下的堆里,一定不能有一组石子堆的异或和为0,这很显然。

所以如果后者选取第二种做法,那么会使得原有的Nim游戏的异或和不为0,所以先手又可以将这个游戏的异或和变为0。

即如果先手开始选取最多石子堆来建立一个异或和为0的nim游戏,则后者必败。

又可以转化一下,如果先手可以选出一个任意数量的石子堆建立的异或和为0的nim游戏,则后者必败。

这很显然。

这道题石子堆的范围是14,所以我们可以 214 直接dfs淦。

或者高斯消元。

不过显然前者啊2333

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 15
using namespace std;
int n;
int a[N];
bool v[N];
int flag;
void dfs(int no)
{
    if(no==n+1)
    {
        int ans=0,cnt=0;
        for(int i=1;i<=n;i++)if(v[i])ans^=a[i],cnt++;
        if(!ans&&cnt!=0)
        {
            flag=1;
        }
        return;
    } 
    v[no]=1;dfs(no+1);
    v[no]=0;dfs(no+1);
}
int main()
{
    int tot=10;
    while(tot--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        memset(v,0,sizeof(v));
        flag=0;
        dfs(1);
        if(flag)puts("NO");
        else puts("YES");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值