【 bzoj 3759 】 Hungergame

本文探讨了一种类似于Nim游戏的策略游戏,通过分析不同状态下先手玩家的胜负情况,给出了先手必胜的充分必要条件,并提供了一个简单的算法实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  似乎是在美术课上听老师扯淡的时候突然YY出来的?
  如果所有的箱子都是打开的,那么就是Nim游戏,直接看Nim和也就是异或和是否为0,是的话先手就输。但是现在有些箱子是打开的,同样也可以尝试用一般Nim游戏的思路来看这道题。
  根据终态,很容易可以出猜测出如果打开的箱子的Nim和为0的时候先手必败。但是这是有条件的,必须要把最大的的Nim和为0的子集先打开,否则即使当前Nim和为0,后手仍然可以把剩余的Nim和为0的子集打开,这样就会改变状态。
  下面分情况讨论一下。
  如果存在Nim和为0的子集,那么先手先把最大的子集打开,此时未开的箱子里不存在Nim和为0的子集。后手如果在开了的箱里取数,就照Nim游戏那样玩。如果后者打开关着的箱,此时开着的箱的Nim和不为0,同样照Nim游戏那样玩。总之不论怎么搞,先手都可以像普通的Nim游戏一样把Nim和取到0。故此时先手必胜。
  如果不存在Nim和为0的子集,那么先手不论开哪些箱,后手总可以使Nim和改为0,故此时先手必败。
  因此就可以得到先手必胜当且仅当存在子集异或和为0的结论。
  数据范围很小,直接暴力状压就能A。
  时间复杂度O(Tn2n)。那些0ms的是smg = =

#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define For(i,a,b) for(int i=a;i< b;i++)
#define shl(i) (1 << (i))

inline int rd() {
    char c = getchar();
    while (!isdigit(c)) c = getchar() ; int x = c - '0';
    while (isdigit(c = getchar())) x = x * 10 + c - '0';
    return x;
}

int n , a[21];

void input() {
    n = rd();
    For (i , 0 , n) a[i] = rd();
}

void solve() {
    int all = shl(n);
    For (s , 1 , all) {
        int sg = 0;
        For (i , 0 , n) if (shl(i) & s) sg ^= a[i];
        if (!sg) {
            puts("Yes");
            return;
        }
    }
    puts("No");
}

int main() {
    #ifndef ONLINE_JUDGE
        freopen("data.txt" , "r" , stdin);
    #endif
    per (T , rd() , 1) {
        input();
        solve();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值