hihocode #1172 : 博弈游戏·Nim游戏·二

106 篇文章 0 订阅
64 篇文章 0 订阅


时间限制: 10000ms
单点时限: 1000ms
内存限制: 256MB
描述

Alice和Bob这一次准备玩一个关于硬币的游戏:
N枚硬币排成一列,有的正面朝上,有的背面朝上,从左到右依次编号为1..N。现在两人轮流翻硬币,每次只能将一枚正面朝上的硬币翻过来,并且可以随自己的意愿,在一枚硬币翻转后决定要不要将该硬币左边的任意一枚硬币也翻一次(正面翻到背面或背面翻到正面)。翻最后一枚正面向上的硬币的人获胜。同样的,这次游戏里面Alice仍然先手,两人均采取最优的策略,对于给定的初始局面,Alice会获胜还是Bob会获胜?

提示:Turning Turtles

输入

第1行:1个正整数N,表示硬币数量。1≤N≤10,000
第2行:1个字符串,第i个字符表示编号为i的硬币状态,’H’表示正面朝上,’T’表示背面朝上。

输出

第1行:1个字符串,若Alice能够获胜输出"Alice",否则输出"Bob"

样例输入
8
HHTHTTHT
样例输出
Bob

解题思路:

这题是白书上翻棋子游戏的简化版,将二维改成了一维,其实道理是一样的。

我们可以把每个正面朝上的第i个硬币都看成一个有i个石子的石子堆,那么就要以下3种后续操作:

1.只把当前硬币翻过来,那么就相当于把整堆石子取完。

2.把当前硬币i翻过来,并且把之前一枚反面朝上的硬币j也翻过来,当前硬币i就无法再操作,而原本无法操作的硬币j就变成可以操作的了,那么就相当于i个石子的石子堆被j个石子的石子堆替代了,其实也就是把i个石子的石子堆删到只剩j个石子。

3.把当前硬币i翻过来,并且把之前一枚正面朝上的硬币j也翻过来,这时候硬币i和硬币j都无法再操作,讲道理就是把两堆石子都取了,但是我们可以转换一下,两个相同的数异或一下也等于0,所以把i个石子的石子堆变成j个石子效果也是一样的,所以也就是把i个石子的石子堆删到只剩j个石子。

那么第i个硬币就和大小为i的石子堆的sg值是一样的,也就是i本身,我们只需要把所有正面朝上的硬币的位置异或一下就得出答案了。


而白书上的翻棋子游戏就是扩展到二维:

题意:一个棋盘上每个格子有一个棋子,每次操作可以随便选一个朝上的棋子(x,y),代表第i行第j列的棋子,选择一个形

(x,b)或(a,y)(其中b < y,a < x)的棋子,然后把它和(x,y)一起翻转,无法操作的人输。

坐标为(x,y)的棋子就可以等价为两堆大小分别为x、y的石子,证明(口胡)跟上面的翻硬币是一样的了,就不在讲了


代码:

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

int main()
{
    int n;
    cin>>n;
    int sg=0, i, j;
    char x;
    scanf("\n");
    for(i=1; i<=n; i++)
    {
        scanf("%c", &x);
        if(x=='H')sg^=i;
    }
    if(sg==0)printf("Bob\n");
    else printf("Alice\n");
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值