天天看点

HDU 3389 Game 阶梯博弈

题目大意:

就是现在给出一些盒子依次编号从1到n, 每个盒子中有一定的卡片, 然后每次可以选择将B中任意数量的卡片放进A中, 其中A, B满足 (A + B) % 2 == 1 && (A + B) % 3 == 0, A < B

轮到谁但是没有可移动的牌那个人就输了, 问谁会获得胜利

大致思路:

首先这个题需要了解一下阶梯博弈:

一个简单的阶梯博弈的模型:

现在有编号1~n的n级阶梯, 每个阶梯上都有自然数个球, 然后每次可以将 i + 1级阶梯的任意数量的球拿到 i 上, 阶梯1上的球不可动, 两个人轮流进行轮到谁不能拿球那个人就输了, 现在在这个模型中可以发现以下事实:

首先1号台阶上的球不能移动

对于偶数编号的台阶, 上面的球到1号台阶需要奇数步, 奇数台阶到达1号台阶需要偶数步, 那么当某人需要改变对自己不利的局势时如果选择移动奇数编号的台阶, 由于这些台阶上的球到达1号台阶是偶数步的, 另外一个人只需要将同样数量的球继续向前移动就是的局面没有变化

于是只有偶数编号的台阶有决定性质, 而当这些台阶的球向前移动到奇数编号的台阶上时就相当于是将这些球拿走了一样, 那些球不再决定胜负了

所以就是偶数编号上的台阶的球做Nim博弈

在上面这个模型中起决定性质的在到达终点是奇数步的点上

而在这题中, 可以发现起决定性质的点编号为C的话满足 (C module 6 == 0, or 2, or 5)

于是就相当于这些位置的卡片的Nim博弈了

代码如下:

Result  :  Accepted     Memory  :  1572 KB     Time  :  0 ms

/*
 * Author: Gatevin
 * Created Time:  2015/5/3 12:10:47
 * File Name: Rin_Tohsaka.cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;
#define foreach(e, x) for(__typeof(x.begin()) e = x.begin(); e != x.end(); ++e)
#define SHOW_MEMORY(x) cout<<sizeof(x)/(1024*1024.)<<"MB"<<endl

int num[10010];

int main()
{
    int T;
    scanf("%d", &T);
    for(int cas = 1; cas <= T; cas++)
    {
        int n;
        scanf("%d", &n);
        for(int i = 1; i <= n; i++)
            scanf("%d", num + i);
        int sg = 0;
        for(int i = 1; i <= n; i++)
            if(i % 6 == 0 || i % 6 == 2 || i % 6 == 5)
                sg ^= num[i];
        printf("Case %d: %s\n", cas, sg ? "Alice" : "Bob");
    }
    return 0;
}