zoukankan      html  css  js  c++  java
  • HDU 2176 取(m堆)石子游戏(Nim)

    取(m堆)石子游戏

    题意:

    Problem Description
    m堆石子,两人轮流取.只能在1堆中取.取完者胜.先取者负输出No.先取者胜输出Yes,然后输出怎样取子.例如5堆 5,7,8,9,10先取者胜,先取者第1次取时可以从有8个的那一堆取走7个剩下1个,也可以从有9个的中那一堆取走9个剩下0个,也可以从有10个的中那一堆取走7个剩下3个.

    Input
    输入有多组.每组第1行是m,m<=200000. 后面m个非零正整数.m=0退出.

    Output
    先取者负输出No.先取者胜输出Yes,然后输出先取者第1次取子的所有方法.如果从有a个石子的堆中取若干个后剩下b个后会胜就输出a b.参看Sample Output.

    Sample Input
    2
    45 45
    3
    3 6 9
    5
    5 7 8 9 10
    0

    Sample Output
    No
    Yes
    9 5
    Yes
    8 1
    9 0
    10 3

    题解:

    这题是否能赢,不用说,是经典NIM,先手,只要异或为0就输,否则赢。
    但要输出取的石子,要想一想。转一个好思路:
    1)如若给出 的是必败状态:a1a2......^an=0,则先手不会有任何可能获得胜利;
    2)若给出的是必胜状态:a1a2.......^an=k,(其中k不为零),那么我们的目的是要把必胜状态转化为必败状态从 而使得先手胜利。若a1a2...an!=0,一定存在某个合法的移动,将ai改变成ai'后满足a1a2...ai'...an=0。若a1a2...^an=k,则一定存在某个ai,它的二进制 表示在k的最高位上是1(否则k的最高位那个1是怎么得到的)。这时aik<ai一定成立。则我们可以将ai改变成ai'=aik,此时a1a2...ai'...an=a1a2...an^k=0。

    代码:

    #include<iostream>
    #include<cstdio>
    using namespace std;
    
    const int MAXN=200000+9;
    int a[MAXN];
    int N;
    int main()
    {
        while(cin>>N,N)
        {
            int sum=0;
            for (int i=0;i<N;i++)
            {
                scanf("%d",a+i);
                sum^=a[i];
            }
            if (sum==0) puts("No");
            else{
                puts("Yes");
                for (int i=0;i<N;i++)
                {
                    int s=sum^a[i];
                    if (s<a[i])
                        printf("%d %d
    ",a[i],s);
                }
            }
        }
    
        return 0;
    }
  • 相关阅读:
    Python分析网页中的<a>标签
    Python3.X爬虫
    如何使你的窗体样式固定,不因系统设定而变化
    C# 窗体内有子控件时鼠标检测
    VS新建项目工具箱图标丢失问题
    在c#中使用bitblt显示图片
    DotNetBar 中Ribbon汉化
    汉化DotNetBar中控件的系统文本
    castle动态代理的使用
    FastReport 套打全攻略
  • 原文地址:https://www.cnblogs.com/s1124yy/p/5705996.html
Copyright © 2011-2022 走看看