Codeforces Round #102 (Div. 1) D Help Shrek and Donkey 2

题目链接:Help Shrek and Donkey 2

题意:一个 n×m 的战场,每行中最多由两个士兵,且只能在同一行种移动。两个玩家,每次每个人可最多选择 k 个自己士兵前进或者撤退(向敌人的方向为前进,向自己的方向为后退),选中的士兵可以移动任意距离,但至少移动 1。当某一方不能移动的时候就为输掉,问这次博弈中谁胜谁负或者平局。

题解:这可以看成一个Moore’s Nim-k。特殊情况特判掉,只需要考虑每一行都有双方的士兵个一个的情况,因为玩家双方都是采取最优策略,假设某一方采取撤退进入必胜态,则另一方可以采取进攻相同的距离到达一开始的状态,所以只用考虑双方都会进攻即可。如此一来,每一堆的数目就是双方士兵之间的距离,由此就成为了一个Moore’s Nim-k了。

 

Moore's Nim-k游戏(抄自网络)

  n 堆石子,每次可以从最多 k 堆中取任意多石子,无法拿石子的人输。

  结论为:把每堆石子的石子数用二进制表示,统计每个二进制位上 1 的个数,若每一位上 1 的个数全为 (k+1) 的倍数,则必败,否则必胜。

证明如下:

  首先,全0为必败态

  对于任何一个二进制位 1 的数目,每次最多改变为 k 。(k+1) 的倍数经过操作后不可能成为 (k+1) 的倍数,同时任意非 (k+1) 的倍数可以经过操作后成为 (k+1) 的倍数,所以所有二进制位 1 的个数之和均为 (k+1) 的倍数时为必败态。

#include <bits/stdc++.h>
using namespace std;

int n,m,k;
char s[105][105];

int num[105];

void solve(){
    for(int i=0;i<n;i++){
        int posG=-1,posR=-1;
        for(int j=0;j<m;j++){
            if(s[i][j]=='G') posG=j;
            if(s[i][j]=='R') posR=j;
        }
        if(posG==-1||posR==-1) num[i]=0;
        else num[i]=abs(posG-posR)-1;
    }
    for(int i=0;i<=10;i++){
        int res=(1<<i);
        int sum=0;
        for(int j=0;j<n;j++){
            sum+=(num[j]/res)%2;
        }
        if(sum%(k+1)){
            printf("First\n");
            return;
        }
    }
    printf("Second\n");
}

int main(){
    cin>>n>>m>>k;
    int all1=0,all2=0,flag=0;
    for(int i=0;i<n;i++){
        cin>>s[i];
        int num1=0,num2=0;
        for(int j=0;j<m;j++){
            if(s[i][j]=='G') num1++;
            else if(s[i][j]=='R') num2++;
        }
        if(num1==0&&num2!=0&&num2!=m) all2++;
        if(num1!=0&&num2==0&&num1!=m) all1++;
    }
    if((all1==0&&all2!=0)){
        printf("Second\n");
        return 0;
    }
    else if(all1!=0&&all2==0){
        printf("First\n");
        return 0;
    }
    else if(all1!=0&&all2!=0){
        printf("Draw\n");
        return 0;
    }

    solve();

    return 0;
}

 

posted on 2019-01-10 14:26  Psong  阅读(254)  评论(0编辑  收藏  举报

导航