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

 

posted @ 2015-08-01 01:20  PlusSeven  阅读(252)  评论(0编辑  收藏  举报