高僧斗法
题目
资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
古时丧葬活动中经常请高僧做法事。仪式结束后,有时会有“高僧斗法”的趣味节目,以舒缓压抑的气氛。
节目大略步骤为:先用粮食(一般是稻米)在地上“画”出若干级台阶(表示N级浮屠)。又有若干小和尚随机地“站”在某个台阶上。最高一级台阶必须站人,其它任意。(如图1所示)
两位参加游戏的法师分别指挥某个小和尚向上走任意多级的台阶,但会被站在高级台阶上的小和尚阻挡,不能越过。两个小和尚也不能站在同一台阶,也不能向低级台阶移动。
两法师轮流发出指令,最后所有小和尚必然会都挤在高段台阶,再也不能向上移动。轮到哪个法师指挥时无法继续移动,则游戏结束,该法师认输。
对于已知的台阶数和小和尚的分布位置,请你计算先发指令的法师该如何决策才能保证胜出。
输入格式
输入数据为一行用空格分开的N个整数,表示小和尚的位置。台阶序号从1算起,所以最后一个小和尚的位置即是台阶的总数。(N<100, 台阶总数<1000)
输出格式
输出为一行用空格分开的两个整数: A B, 表示把A位置的小和尚移动到B位置。若有多个解,输出A值较小的解,若无解则输出-1。
样例输入
1 5 9
样例输出
1 4
样例输入
1 5 8 10
样例输出
1 3
思路
看了一下其他大佬写的博客,感觉写的都挺模糊的。。。至少我看的别扭
新入坑博弈的可以借鉴这位巨巨的基本博弈论博客:https://blog.youkuaiyun.com/QLU_minoz/article/details/88613618
本题也就是一个类似于阶梯尼姆博弈(Nim Staircase博奕)的一个尼姆博弈扩展。不能直接用尼姆博弈咱们就可以用一下阶梯尼姆的思维嘛。
咱们先不考虑所有和尚的移动,咱就移动序号为奇数的和尚,当能将奇数位和尚与下一位和尚的距离的异或和为0(奇异局势,后手必胜)时,就输出。
为什么?
以我们的样例二来看,1 5 8 10,两个奇数位与下一位的间距分别为3 1,我们移动1到3时,间距分别为1 1,异或和为0,那么不管对手怎么移动,移动的是奇数位还是偶数位,我都可以再次将异或和变为0。
比如他移动第一个偶数位的5到6或7,那么我们第一个奇数位与下一位的距离也随之变大,我们一样可继续将距离变为1
比如他移动第一个奇数位的3(我们先手移动1到3了嘛)到4,那么我们能移动第二个奇数位8到9,使异或和继续为0,那么他只能移动偶数位,操作如上。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int a[1000];
int b[1000];
int yh;
string s;
int main()
{
getline(cin,s);
int si=s.size();
int p=0,num=0;
for(int i=0;i<si;i++)
{
if(s[i]>='0'&&s[i]<='9')
{
p=p*10+(s[i]-'0');
}
else
{
a[++num]=p;
p=0;
}
}
if(p)
{
a[++num]=p;
}
//以上为我习惯的获取整数的方法
for(int i=2;i<=num;i++)
{
b[i-1]=a[i]-a[i-1]-1;
}
for(int i=1;i<num;i+=2)
{
yh^=b[i];
}
if(!yh)
{
printf("-1\n");
return 0;
}
//数据本身为奇异局势,没救了输出-1
for(int i=1;i<num;i++)
{
for(int j=1;a[i]+j<a[i+1];j++)
{
b[i]-=j;
if(i!=0)
b[i-1]+=j;
yh=0;
for(int k=1;k<num;k+=2)
{
yh^=b[k];
}
if(yh==0)//奇异局势
{
printf("%d %d\n",a[i],a[i]+j);
return 0;
}
b[i]+=j;//不能到达奇异局势则还原继续遍历
if(i!=0)
b[i-1]-=j;
}
}
return 0;
}