poj 1704 Georgia and Bob(博弈)

【题目大意】:一个1*M的棋盘上有N个棋子,初始位置一定,两人轮流操作,每次移动一枚棋子,要求只能向左移且至少移动一格,
而且不能到达或经过以前有棋子的格子,谁无法移动棋子就算输。


【解题思路】:1)按照位置进行排序,然后将每两个分成一组
              2)接下来,分下面两种情况讨论:
                     1、先手移动任意组中的左边的一个,那么对于后手的最优策略便是将该组右边的一个移动相同的步数
                     2、先手移动任意组中的右边的一个,我们就要考虑左右之间的间隔差来判断最优策略
              3)分析到这里,其实问题变得更简单了,主要是更熟悉了,接下来看看下面的这个问题:
                    给定N堆石子,每堆里面的石子个数都是非负的。每次可以把第i堆中的任意颗石子移动到第i + 1堆中(1 <= i < N),或者第N堆的石子扔掉任意颗。如果某人不能继续操作则判负。
            
                     (o(∩_∩)o ~~熟悉勒)
              4)对于这一类的取石子问题,我们一般有如下的结论:设第i堆的石子数为ai。设ans=aN xor a(N - 2) xor a(N - 4) xor ... xor a2(a1),若ans=0则先手必败,否则先手必胜。 
              
              5)接下来,证明:

                     首先,显然有当各堆的石子数均为0的时候先手必败。此时ans=0。
                     其次,要证明该结论,只需证明如果ans<>0的时候一定可以通过一步操作将ans变为0,且ans=0的时候任意操作均会使得ans<>0。

                     1、先证明ans<>0的时候可以将ans->0。设此时的ans=x且x的最高位"1"是第k位,则一定存在某个 i=总堆数-2n(n ∈ N),使得a(i)的第k位也为1,否则第k位的异或运算的值不可能为1。将ai改变为ai' = x xor ai,由于ai的第k位以上的位不会改变,第k位由1变成了0,易知ai'<ai。故只需将ai的石子向右移动(ai-ai')个即可。由奇偶性可知ai右边的一堆不参与运算。

                     此时ans=x xor ai xor ai' =x xor ai xor (x xor ai) = 0。

                     2、再证ans=0时无论怎么操作均会使ans<>0。设x=0时设将ai改变成了ai',显然ai<>ai'。

                     此时ans=x xor ai xor ai' = ai xor ai' <> 0。

      

               ~~~结束了


【代码】:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <cmath>
#include <string>
#include <cctype>
#include <map>
#include <iomanip>
                   
using namespace std;
                   
#define eps 1e-8
#define pi acos(-1.0)
#define inf 1<<30
#define pb push_back
#define lc(x) (x << 1)
#define rc(x) (x << 1 | 1)
#define lowbit(x) (x & (-x))
#define ll long long

int n;
int p[10100];
int T, i, j, a, cnt, t;

int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        cnt=0;
        for(i=1; i<=n; i++) scanf("%d",&p[i]);
        sort(p+1,p+n+1);
        int k=1;
        for(i=n; i>=2; i-=2){
            t=p[i]-p[i-1]-1;
            cnt=cnt^t;
        }
        if(n%2==1) cnt=cnt^(p[1]-1);
        if(cnt!=0) cout << "Georgia will win" << endl;
        else cout << "Bob will win" << endl;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值