Gym101353D ShaatChara (博弈模板)

Gym101353D ShaatChara (博弈模板)


题目链接

hdu上类似的一个题,帮助理解题意

大佬的题解

深入理解按位异或运算符

博弈模板

异或运算符
这里写图片描述

题意及反省
题意理解错了,导致第三个样例不能理解,
开始以为,假如在我可能胜利的情况下,我要取几次才能够让自己不败,有下面两种情况,
(1)异或值为0,先手必败,以最优的策略,
我自己最少要取一次来改变当前的局面,让自己不败。
(考虑1 1 的情况?必败:按照题意,每个人每一次取,都必须从某一堆石子中取走至少一颗)
(2)异或值为1,先手必胜,我可以不必取。
很混乱了,代码好像逻辑上都讲不通,因为思路的逻辑本来就不对。

后面看了大佬的博客,
题意:
“就是假如第一个人能胜利的情况下,他的第一次取物品,能从哪几堆取,可以继续保持胜利,输出这个堆数。能让他保持胜利的方式是:他取完后,所有物品数的异或值变为0。”
(如果第一个人必败的情况下,直接输出0,因为他不能采取任何行动来取胜
举例:样例2异或值为0,先手必败,输出0)

补充:
He wants to know how many possible moves he may take such that
Meena’s win does not become guaranteed.
他想知道的是,他可能会采取多少可能的行动,而米纳斯的胜利并没有得到保证。

游戏规则:
The game is for two players. Each player takes turn alternatively.
In each turn a player can select any of the piles that has at least 1 stone left, and then remove some stone (at least one) from it.
The game goes on like this until there are no stones left. The player who can’t make a move loses.

ac代码

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <stdlib.h>

using namespace std;

const int maxn=10050;
int arr[maxn];

int main()
{
    int t,n,cnt=0;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        int tmp=0,ans=0;  // tmp = 0 :0异或任何数=任何数
        for(int i=0; i<n;++i)
        {
            scanf("%d",&arr[i]);
            tmp^=arr[i];
        }
        for(int i=0; i<n; i++)
            if(arr[i]>(tmp^arr[i]))
            /*
              大于号右边的表达式的意思是除了第i堆,其它所有堆的物品数的异或值。
              因为 0异或任何数=任何数,前面tmp已经保存了所有堆数的异或值。
              举个例子,tmp = a^b^c^d, 所以tmp^a = a^a^b^c^d = b^c^d。

              如果第i堆的物品数大于这个异或值,第i堆的物品数就可以减去一个值等于这个异或值,
              这样我们就可以得到两个相等的异或值,而 两个相等的数异或值为0,0异或任何数=任何数,
              我们就能够保持原来的先手必胜的局面。
            */
            ans++;
        printf("Case %d: %d\n",++cnt,ans);
    }
    return 0;
}

混乱的代码

#include <stdio.h>

int
main() {
    int t, n, i, k = 0, ans, a[10005];

    scanf("%d", &t);
    while( t-- ) {
        scanf("%d", &n);
        for( i = 0; i < n; i++ ) {
            scanf("%d", &a[i]);
        }
        if( n == 1 ) {
            printf("Case %d: 1\n", ++k);
        }
        else {
            ans = a[0];
            for( i = 1; i < n; i++ ) {
                ans ^= a[i];
            }
            if( ans == 0 ) {
                printf("Case %d: 0\n", ++k);
            }
            else {
                printf("Case %d: %d\n", ++k, n);
            }
        }
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值