• HDU1850 尼姆博弈求可行方案数目


    尼姆博弈(Nimm's Game)

    题型

    尼姆博弈模型,大致上是这样的:

    有3堆各若干个物品,两个人轮流从某一堆取任意多的物品,规定每次至少取1个,多者不限,最后取光者得胜。

    分析

    1、首先自己想一下,就会发现只要最后剩两堆物品一样多(不为零),第三堆为零,那面对这种局势的一方就必败

    那我们用(a,b,c)表示某种局势,首先(0,0,0)显然是必败态,无论谁面对(0,0,0) ,都必然失败;第二种必败态是(0,n,n),自己在某一堆拿走k(k ≤ n)个物品,不论k为多少,对方只要在另一堆拿走k个物品,最后自己都将面临(0,0,0)的局势,必败。仔细分析一下,(1,2,3)也是必败态,无论自己如何拿,接下来对手都可以把局势变为(0,n,n)的情形

    那这种奇异局势有什么特点呢?

    也不知谁这么牛逼,竟然能把这种局势和二进制联系在一起

    这里说一种运算符号,异或'^',a^b=a'b+ab'(a'为非a)

    我们用符号XOR表示这种运算,这种运算和一般加法不同的一点是1 XOR 1 = 0。先看(1,2,3)的按位模2加的结果:

    1 = 二进制01

    2 = 二进制10

    3 = 二进制11  XOR

    ———————

    0 = 二进制00 (注意不进位)

    对于奇异局势(0,n,n)也一样,结果也是0

    任何奇异局势(a,b,c)都有a XOR b XOR c = 0

    如果我们面对的是一个非必败态(a,b,c),要如何变为必败态呢?

    假设 a < b < c,我们只要将 c 变为a XOR b,即可。因为有如下的运算结果:

    a XOR b XOR (a XOR b)=(a XOR a) XOR (b XOR b) = 0 XOR 0 = 0

    要将c 变为a XOR b,只要对 c进行 c-(a XOR b)这样的运算即可

    Being a Good Boy in Spring Festival

    Problem Description

    一年在外 父母时刻牵挂
    春节回家 你能做几天好孩子吗
    寒假里尝试做做下面的事情吧

    陪妈妈逛一次菜场
    悄悄给爸爸买个小礼物
    主动地 强烈地 要求洗一次碗
    某一天早起 给爸妈用心地做回早餐

    如果愿意 你还可以和爸妈说
    咱们玩个小游戏吧 ACM课上学的呢~

    下面是一个二人小游戏:桌子上有M堆扑克牌;每堆牌的数量分别为Ni(i=1…M);两人轮流进行;每走一步可以任意选择一堆并取走其中的任意张牌;桌子上的扑克全部取光,则游戏结束;最后一次取牌的人为胜者。
    现在我们不想研究到底先手为胜还是为负,我只想问大家:
    ——“先手的人如果想赢,第一步有几种选择呢?”

    Input

    输入数据包含多个测试用例,每个测试用例占2行,首先一行包含一个整数M(1<M<=100),表示扑克牌的堆数,紧接着一行包含M个整数Ni(1<=Ni<=1000000,i=1…M),分别表示M堆扑克的数量。M为0则表示输入数据的结束。

    Output

    如果先手的人能赢,请输出他第一步可行的方案数,否则请输出0,每个实例的输出占一行。

    Sample Input

    3

    5 7 9

    0

    Sample Output

    1

    分析:由上分析可知,只要能对 c进行取走(c-(a XOR b))这样的操作即为可行方案

    代码如下:

    #include<iostream>
    #include<string.h>
    using namespace std;
    int main()
    {
        int n,p[111];
        while(~scanf("%d",&n)&&n)
        {
            int sum=0;
            for(int i=0;i<n;i++)
            {
                scanf("%d",&p[i]);
                sum^=p[i];
            }
            if(!sum)//奇异局势
            {
                printf("0
    ");
                continue;
            }
            else
            {
                int cnt=0;
                for(int i=0;i<n;i++)
                {
                    if((sum^p[i])<p[i])//此方案下取p[i]-sum^p[i]张形成奇异局势
                        cnt++;
                }
                printf("%d
    ",cnt);
            }
        }
        return 0;
    }
    

    部分转自:https://www.cnblogs.com/jiangjun/archive/2012/11/01/2749937.html

  • 相关阅读:
    hdu6055(求正方形个数)
    树状数组模板(改点求段 / 该段求点 / 改段求段)
    poj2763(lca / RMQ + 线段树)
    poj3728(lca / tarjan离线)
    JDK8-废弃永久代(PermGen)迎来元空间(Metaspace)
    JVM垃圾回收机制
    虚拟机字节码执行引擎
    Java中程序初始化的顺序
    Java中ClassLoader浅析.
    Python中的self
  • 原文地址:https://www.cnblogs.com/aeipyuan/p/9502683.html
Copyright © 2020-2023  润新知