H - 阶梯 - NIM博弈1 POJ - 1704 (hh2048题单)

 

 

【题目大意】:

  在棋盘上有n个棋子,Bob 与 Georgia 轮流下棋 。Georgia先手(因为她是女生)。

  每个选手都可以选择一颗棋子,将棋子往左边移动任意格(这个棋子的左边不能是边界或者越过)

  最后能操作的人赢。问谁会赢。

【思路】:

  阶梯博弈的思路。

  阶梯博弈的关键点(自己当前的想法):

1。要统计出所有的终止位置,棋子到了这个终止位置后不能有其他操作 。

2。所有棋子的位置最后都要落到终止位置。

3。原始状态存在抵消操作:  比如到终止位置的步数可以始终保持偶数,那么后手就可以模仿先手的操作进行抵消,进入到终止状态,那么就不影响游戏结果

4。将会对游戏产生影响的操作进行异或操作,求出最后的答案。如果存在走到奇数的情况,那么后手就不能一直效仿先手的操作,要进行变招,这时候就会影响游戏结果,变成nim游戏。

第4点的解释:如果会产生影响,那么将其看成一个独立游戏,这个独立游戏不会对其他情况产生影响,所以异或他们的sg值。

  左边界的下标是0。终止状态就是当棋子移到了0的位置,然后一个个紧贴着排下去。   这显然是终止状态并且是唯一的终止状态,并且最终都会到这个状态。

  当两个棋子紧贴的时候,先手如果移动前面的棋子,那么后手只要移动后面的棋子,那么又能回到紧贴的状态,不会对游戏产生影响。

  如果一对棋子不是紧贴,那么不管先手将前面的棋子移动多少格,后手都能移动后面的棋子(因为中间不会存在边界,或者有其他棋子的情况),始终能保持住这个状态。

  如果先手主动移动一对棋子中后面的那个,那么先手有可能不能保持原来的状态(比如左边就是边界,或者左边存在棋子),会导致游戏产生变化。

  每对棋子相当于一次简单游戏,他们间的空隙大小相当于棋子数。

    如果这对棋子是紧贴的,那么sg(0) = 0

    如果空隙为1格, 那么sg(1) = mex(sg(0)) =1 

    空隙为2格,sg(2) = mex(sg(0),sg(1)) = 2

  所以sg(x) =  x。

  只需要对所有简单游戏进行异或操作(nim思想),那么就能求出先手必赢还是后手必赢。

【代码】:

  

#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <vector>
#include <stack>
#include <bitset>
#include <cstdlib>
#include <cmath>
#include <set>

#define ms(a, b) memset(a,b,sizeof(a))
#define fast ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define ll long long
#define ull unsigned long long
#define rep(i, a, b)  for(ll i=a;i<=b;i++)
#define lep(i, a, b)  for(ll i=a;i>=b;i--)
#define endl '\n'
#define pii pair<int, int>
#define pll pair<ll, ll>
#define vi  vector<ll>
#define vpi vector<pii>
#define vpl vector<pll>
#define mi  map<ll,ll>
#define all(a)  (a).begin(),(a).end()
#define gcd __gcd
#define pb push_back
#define mp make_pair
#define lb lower_bound
#define ub upper_bound

#define ff first
#define ss second
#define test4(x, y, z, a) cout<<"x is "<<x<<"        y is "<<y<<"        z is "<<z<<"        a is "<<a<<endl;
#define test3(x, y, z) cout<<"x is "<<x<<"        y is "<<y<<"        z is "<<z<<endl;
#define test2(x, y) cout<<"x is "<<x<<"        y is "<<y<<endl;
#define test1(x) cout<<"x is "<<x<<endl;
using namespace std;
const int N = 1e5 + 10;
const int maxx = 0x3f3f3f;
const int mod = 1e9 + 7;
const int minn = -0x3f3f3f;
const int M = 2 * N;
ll T, n, m;
ll a[N] , d[N] ;
void solve() {
    cin>>n;
    d[0] = 0;
    a[0] = 0;
    rep(i,1,n){
        cin>>a[i];
    }
    sort(a+1,a+1+n);
    int res = 0;
    for ( int i=n;i>0;i-=2){
        res ^= (a[i]-a[i-1]-1);
    }
    if( res )   cout<<"Georgia will win"<<endl;
    else cout<<"Bob will win"<<endl;
}

int main() {
    fast;
    cin >> T;
    while (T--) {
        solve();
    }
    return 0;
}
View Code

 

posted @ 2022-04-12 15:11  Pan_c  阅读(70)  评论(0)    收藏  举报