zoukankan      html  css  js  c++  java
  • POJ 1740 A New Stone Game(普通博弈)

    A New Stone Game

    题意:

    对于n堆石子,每堆若干个,两人轮流操作,每次操作分两步,第一步从某堆中去掉至少一个,第二步(可省略)把该堆剩余石子的一部分分给其它的某些堆。最后谁无子可取即输。

    题解:

    首先我们考虑两堆相等的情况,一定是谁取谁输,因为对方永远可以做对称的操作。对于四堆,1、2堆相等,3、4堆相等的情况,一定也是先手输,后手也只需要做对称的操作(在先手取石子的对称堆中取相同多的石子,并把和先手等量的石子分给先手分配给的堆的对称堆。(若先手在3堆取,并分给1堆,那后手就在4堆取,分给2堆)。也就是说对于任意的一对一对相等的情况来说,一定是后手必胜。

    我们接下来来证明除上述情况外,所有情况都是先手必胜。因为任何一种情况都可以转化为一对一对相等的情况。若总堆数为奇数的情况,可以把石子最多的一堆的石子分配给其它堆,使得其它堆两两相等。最多一堆的石子绝对是足够多,可以完成这个补齐的任务的。因为我们把石子从小到大排序后画成条形统计图。把相邻两个分成一组(1和2一组,3和4一组……)我们需要用第n堆填补1,3,5……堆我们把需要填补的这些差距(2比1高出的部分,4比3高出的部分……)投影到统计图左侧的y轴上,我们会发现这是一些不连续的区间,其长度总和明显小于第n堆。所以可以补齐。

    对于堆数为偶数的情况。我们把最多的一堆削弱到和最少的一堆一样多,并把拿掉的石子分给别的堆,使其一对一对地相等。可行性于前面奇数情况同理。

    所以只要判断是不是一对一对的相等的情况即可。

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    using namespace std;
    
    bool f[1005];
    
    int main()
    {
        //freopen("t.txt", "r", stdin);
        int n;
        while (scanf("%d", &n), n)
        {
            memset(f, 0, sizeof(f));
            int ans = 0;
            for (int i = 0; i < n; i++)
            {
                int a;
                scanf("%d", &a);
                if (f[a])
                    ans--;
                else
                    ans++;
                f[a] = !f[a];
            }
            if (ans)
                printf("1
    ");
            else
                printf("0
    ");
        }
        return 0;
    }
  • 相关阅读:
    HDU
    C# Stopwatch
    RMQ(Range Minimum Query)问题(转)
    HDU
    POJ
    HDU
    POJ
    POJ
    docker安装testlink
    廖雪峰Java2面向对象编程-3继承和多态-2多态
  • 原文地址:https://www.cnblogs.com/s1124yy/p/5702694.html
Copyright © 2011-2022 走看看