【bzoj3759】【hungergame】【线性基+博弈论】

Description

由于施惠国的统治极其残暴,每年从13个区中每个区中选出2名“贡品”参加饥饿游戏,而参加游戏的人必须在险恶的自然环境中杀死其余的人才能存活。游戏只会有一个人活下来 凯特尼斯•伊夫狄恩和同区的皮塔•麦拉克在历经千难万阻后活了下来,然而残忍的游戏只允许一人存活,正当两人准备同时吃下有毒的果实自杀的时候,统治者被打动了,他说:你们两个人跟我玩一个游戏,你赢了,我就让你们两个都活下来。女主角凯特尼斯•伊夫狄恩接受了挑战。
这个游戏是这样的,有n(n<=20)个箱子,每个箱子里面有ai(ai<=1000000000)个石头(怎么放进去的我就不知道了),两个人轮流进行操作(女主角先手),每一次操作可以将任意个(大于0个)未打开的箱子打开(一开始所有的箱子都是关闭的),或者在已经打开的一个箱子里拿走任意个(大于0个)石头(不能超过这个箱子现有的石头数)。最后谁无法操作谁就输了。
现在给出n,和这n个箱子里的石头数ai,女主角想知道她是否有绝对的把握取得胜利(很明显她的对手“统治者”是绝顶聪明的)。

Input

第一行有一个正整数T(表示有T组测试数据),对于每组测试数据有两行,第一行为一个正整数n,接下来有 n个数,第 i 个数表示ai.

Output

 有T行:对于每一个测试数据,如果先手可以必胜则输出“Yes”,否则输出“No”(没有引号)。

Sample Input

5
5
18 11 16 19 15
5
18 12 17 10 18
5
17 7 1 10 1
5
19 5 16 19 8
5
18 18 7 4 9

Sample Output

No
Yes
Yes
Yes
Yes

HINT

100%的数据:n<=20,T<=10,ai不超过1,000,000,000;
题解:类似nim游戏。
           若当前已经打开的箱子的异或和为0,并且没打开的箱子中不存在异或和为0的子集和。
           那么一定是先手必败的。
           我们考虑先手一共有两种选择。
           如果拿石子的话后手一定可以对应的拿石子重新回到之前的状态。
           如果开箱子的话后手也一定可以对应的拿石子回到之前的状态。
           所以初始时只要存在一个子集和的异或和为0那么先手一定必胜。
           所以只要判断是否存在这样的子集。
           直接用线性基即可。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int t,n,a[100];
bool cal(){
  int i,j,k(0);
  for (i=1<<30;i;i>>=1){
    for (j=k+1;j<=n;j++)if (a[j]&i)break;
    if (j==n+1) continue;k++;
    swap(a[k],a[j]);
    for (j=1;j<=n;j++) 
      if (j!=k&&(a[j]&i)) a[j]^=a[k];
  }
  return k!=n;
}
int main(){
 scanf("%d",&t);
 while (t--){
   scanf("%d",&n);
   for (int i=1;i<=n;i++) scanf("%d",&a[i]);
   if (cal()) cout<<"Yes"<<endl;
   else cout<<"No"<<endl;
 }
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值