• Nim及SG函数


    HDU 4315

    题目:山上有n个人,每个人给出距离山顶的距离,给出其中一个人为king,每次能挑选一个人向上移动,不能越过其他人,最后将king移动到山顶者获胜。问获胜者。

    思路:转化为NIM游戏。

    简记:

    NIM游戏:有n堆石子,每次可以选择一堆拿走任意数量的石子,不能拿石子的一方失败。

    NIM游戏的必败态为所有堆的石子数目异或值为0的情况,那是因为,如果异或值不为0,设其为x,x的二进制表示中的最左边的一位1必然存在一堆(设为z)与之对应,将这一堆取成y=x^z,那么得到的状态为异或值为0(必败态),而必败态不论如何取,后继状态必然为必胜态。(具体参考《算法竞赛入门经典训练指南》)

    本题与NIM游戏的关系与转化。

    如果k=1,那么显然先手必胜。

    先考虑一个简化问题:不考虑king,当不能移动时为败。

    首先注意到一个必败:如果n为偶数,且所有奇数位的人与其后的人均紧靠,那么此时为必败态,因为不论先手如何移动(只可能移动奇数位),后手必然可以移动偶数位使其依然保持紧靠。如果加入考虑king,那么k为偶数时,同上讨论,先手必败,如果k为奇数,那么可以把游戏看为移动k-1位置的人到1(由前讨论,后手可以达到这一目标),故k为奇数时仍然为先手必败态。

    此时我们就可以考虑如何将游戏进行至必败态,如果先手移动奇数位,那么后手总可以移动偶数位使得相隔距离不变,所以问题可以只考虑奇数位和其后相邻的偶数位的间距,把他们看成NIM堆,移动对应减少石子,当石子数为0时就是紧靠的必败态。

    当n为奇数时,如果k不等于2,那么可以把第一个人到山顶看成一堆石子,当NIM游戏结束时第一个人到达山顶,情况就变得和偶数时一样。

    如果k等于2,那么第一个人到山顶就是必败态,故第一个人最多能到1的位置,第一堆石子数减一。

    主要思路参考kuangbin大神:http://www.cnblogs.com/zhourongqing/archive/2012/07/28/2613679.html

    #include <iostream>
    #include <map>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <functional>
    #include <set>
    #include <cmath>
    #define pb push_back
    #define fs first
    #define se second
    #define sq(x) (x)*(x)
    #define eps 0.0000000001
    #define IINF (1<<30)
    using namespace std;
    typedef long long ll;
    typedef pair<ll,ll> P;
    const int maxv=1005;
    int n,k;
    int a[maxv];
    int main(){
        freopen("/home/files/CppFiles/in","r",stdin);
        /*    std::ios::sync_with_stdio(false);
            std::cin.tie(0);*/
        while(cin>>n>>k){
            for(int i=0;i<n;i++){
                scanf("%d",a+i);
            }
            if(k==1){
                puts("Alice");
                continue;
            }
            if(n%2==0){
                int res=0;
                for(int i=1;i<n;i+=2){
                    res^=a[i]-a[i-1]-1;
                }
                if(res==0){
                    puts("Bob");
                }else{
                    puts("Alice");
                }
            }else{
                int res=0;
                if(k==2){
                    res^=a[0]-1;
                }else{
                    res^=a[0];
                }
                for(int i=2;i<n;i+=2){
                    res^=a[i]-a[i-1]-1;
                }
                if(res==0){
                    puts("Bob");
                }else{
                    puts("Alice");
                }
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    hdu 4864 Task
    hdu 1501 Zipper
    hdu 1428 漫步校园
    hdu 1505 City Game
    hdu 1337 The Drunk Jailer
    9-13记录
    python 读取unicode编码文件
    梯度出现Nan值的追踪
    Rstudio-server更改R版本
    stdout/stderr作用学习
  • 原文地址:https://www.cnblogs.com/Cw-trip/p/4693519.html
Copyright © 2020-2023  润新知