Nim博弈
给出n堆石子,每堆有若干个石子,每次可以向任意堆石子中取任意多个石子,谁最后不能取石子谁输。
结论:将每堆石子数作异或和
若异或和为0,先手必败。
若异或和不为0,先手必胜。
http://acm.hdu.edu.cn/showproblem.php?pid=4315
大意:按编号大小顺序给出n个人的位置编号,山顶的编号是0,国王的位置编号是第k个人的位置编号,每次可以将一个人从当前位置向左移向任意位置,但不能超越左边的人,也不能两个人占用同一个人的位置。谁先把国王移动到山顶谁就赢。
思路:这题并不能直接看出是Nim博弈。依据题意可知,每个人移动的范围是当前位置和左边第一个人位置之间的位置。其实这之前的位置就可以看成是一堆石子,为什么这样说呢?假设左右两个人的分别是a,b,如果此时就是必胜态,下一次如果将a向左移动,那么下下次就将b向左移动相同的距离,此时还是必胜态,如果将b向左移动,不就相当于在这一堆石子里面取走石子吗?所有将两两之间的空位置作为一堆石子,然后就按照nim博弈的做法去做就行。当n为奇数时,我们将最终位置和第一个人的位置组成一队。
注意:因为这题是要将国王移到0就赢,所有如果k=1,先手直接将国王移到0,所有必胜。如果k=2,并且n为奇数,此时谁都不想将国王前面那个人移到0,因为这样的话,下一个人一定可以将国王直接移到0,所以次数第一个人要和1组队,而不是0.
Code
#include <bits/stdc++.h>
#define ull unsigned long long
#define ll long long
const int inf = 0x3f3f3f3f;
const ll mod = 1e9+7;
const int N = 2e6+7;
const ll ds = 1e15+7;
const double PI = 3.141592653589793238462643383;
using namespace std;
int a[N];
void solve(){
int n,k;
while(cin >> n >> k){
for(int i = 1; i <= n; i++){
cin >> a[i];
}
if(k == 1) {
cout << "Alice\n";
continue;
}
int ans = 0,tmp;
if(n&1){
ans = a[1];
if(k == 2) ans--;
for(int i = 2; i < n; i++){
tmp = (a[i+1]-a[i]-1);
ans ^= tmp;
}
}
else{
for(int i = 1; i < n; i += 2){
tmp = (a[i+1]-a[i]-1);
ans ^= tmp;
}
}
if(ans) cout << "Alice\n";
else cout << "Bob\n";
}
}
int main(){
// int t;
// cin >> t;
// while(t--)
solve();
//system("pause");
return 0;
}