1739. 高僧斗法

把和尚两两配对,如 1,2 配对; 3,4 配对。每对和尚之间相隔多少个台阶就是多少个石子,配对的一对和尚就是一个石子堆。那么我们就把原题目转化为了 Nim 游戏。

如果是共有奇数个和尚,那么落单的那个可以认为是数量为 0 的石子堆。

每次取石子 x 个,等效于将配对的第一个和尚(即第奇数个)向前移动 x 步。

两两配对的正确性证明:

如果移动随便一个和尚 p 步,那么下一个人可以跟随着移动它的上一个和尚 p 步,不断这么操作。这样的情况递归下去就是,假设移动第 i 个和尚 p 步,那么接下来 i 步会使得前 i 个和尚都往前移动了 p 步。当 i 是偶数时,可以保证在局面(先后手次序)不变的情况下,使得整体往右平移,最终使得第偶数个和尚与下一个和尚的距离都等价变成 0 。即所有第偶数个和尚都无法移动为止。此时只有第奇数个和尚是能够移动的。

对共有奇数个和尚时,因为最后一个和尚的位置按照题意本来就是最高级台阶,他本来就是不能移动的,不用管他即可。

因此,转化后,根据 Nim 游戏规律,异或和为 0 先手必败,否则先手必胜。

因为数据量很小,我们可以暴力枚举所有第一步移动状态,枚举所有的将第 i 个和尚移动 j 步,重新计算间隔,然后看看这么做之后新的 Nim 游戏石子堆异或和是不是为 0 ,是的话走完先手必败,即没走先手必胜。

#include <bits/stdc++.h> using namespace std; #define mn 102 int m[mn],n,v,s[mn],sum; signed main() { while(scanf("%d",&v)!=EOF) m[++n]=v; for(int i=1;i<n;++i) s[i]=m[i+1]-m[i]-1; for(int i=1;i<n;i+=2) sum^=s[i]; if(sum==0) return printf("-1")&0; for(int i=1;i<n;++i) for(int j=1;m[i]+j<m[i+1];++j) { s[i]-=j;//将第i个和尚走j步 if(i!=1) s[i-1]+=j;//对应影响 sum=0; for(int k=1;k<n;k+=2) sum^=s[k]; if(sum==0) return printf("%d %d",m[i],m[i]+j)&0; s[i]+=j;//回溯 if(i!=-1) s[i-1]-=j; } return 0;//程序代码不可能走到这里 }