古时丧葬活动中经常请高僧做法事。
仪式结束后,有时会有“高僧斗法”的趣味节目,以舒缓压抑的气氛。
节目大略步骤为:先用粮食(一般是稻米)在地上“画”出若干级台阶(表示N级浮屠)。
又有若干小和尚随机地“站”在某个台阶上。
最高一级台阶必须站人,其它任意。(如图所示)
两位参加斗法的法师分别指挥某个小和尚向上走任意多级的台阶,但会被站在高级台阶上的小和尚阻挡,不能越过。
两个小和尚也不能站在同一台阶,也不能向低级台阶移动。
两法师轮流发出指令,最后所有小和尚必然会都挤在高段台阶,再也不能向上移动。
轮到哪个法师指挥时无法继续移动,则游戏结束,该法师认输。
对于已知的台阶数和小和尚的分布位置,请你计算先发指令的法师该如何决策才能保证胜出。
输入数据为一行用空格分开的N个整数,表示小和尚的位置。台阶序号从1算起,所以最后一个小和尚的位置即是台阶的总数。(N<100, 台阶总数<1000)
输出为一行用空格分开的两个整数: A B, 表示把A位置的小和尚移动到B位置。
若有多个解,输出A值较小的解,若无解则输出-1。
例如:
用户输入:
1 5 9
则程序输出:
1 4
再如:
用户输入:
1 5 8 10
则程序输出:
仪式结束后,有时会有“高僧斗法”的趣味节目,以舒缓压抑的气氛。
节目大略步骤为:先用粮食(一般是稻米)在地上“画”出若干级台阶(表示N级浮屠)。
又有若干小和尚随机地“站”在某个台阶上。
最高一级台阶必须站人,其它任意。(如图所示)
两位参加斗法的法师分别指挥某个小和尚向上走任意多级的台阶,但会被站在高级台阶上的小和尚阻挡,不能越过。
两个小和尚也不能站在同一台阶,也不能向低级台阶移动。
两法师轮流发出指令,最后所有小和尚必然会都挤在高段台阶,再也不能向上移动。
轮到哪个法师指挥时无法继续移动,则游戏结束,该法师认输。
对于已知的台阶数和小和尚的分布位置,请你计算先发指令的法师该如何决策才能保证胜出。
输入数据为一行用空格分开的N个整数,表示小和尚的位置。台阶序号从1算起,所以最后一个小和尚的位置即是台阶的总数。(N<100, 台阶总数<1000)
输出为一行用空格分开的两个整数: A B, 表示把A位置的小和尚移动到B位置。
若有多个解,输出A值较小的解,若无解则输出-1。
例如:
用户输入:
1 5 9
则程序输出:
1 4
再如:
用户输入:
1 5 8 10
则程序输出:
1 3
#include<iostream>
using namespace std;
/*
该问题可以转化为尼姆堆问题,将和尚们从小到大,两两分为一组,则每一组和尚之间的台阶数可以看做一堆石子的个数。
特殊的是,这些“石子”的个数是可以增加的。当然,这样反而方便于用异或处理。
两两分组时,若和尚个数为偶数,最后一和尚参与分组;若为奇数,最后一个和尚不参与分组。
因为我们只用考虑每一组的两个和尚之间的台阶数,而第二种情况下最后两个和尚之间的台阶可以视为组与组之间的台阶,所以两种分组方法都不影响结果。
*/
int fun(int x[],int count) {
int sum = 0;
for (int i = 0; i < count - 1; i+=2) {
sum ^= x[i + 1] - x[i]-1; //注意是中间的台阶数而不是相差的台阶数
}
if (sum == 0) {
return 0;
}
else
return 1;
}
void solve(int x[],int count) {
for (int i = 0; i < count - 1; i++) {
for (int k = x[i] + 1; k < x[i + 1]; k++) { //对每一个先手方可以移动的和尚,遍历其可能的移动方法
int old = x[i];
x[i] = k;
if (fun(x,count) == 0) { //再将移动后的局面交给fun函数判断对手有没有必赢解法
cout << old << " " << k << endl; //如果某一步导致对手必输,则先手方赢,输出此时的走法,即为A最小的方法
return;
}
x[i] = old;
}
}
cout << "-1" << endl; //若对手始终有必赢解法,则先手方输,输出-1
}
int main() {
int a[100];
int count = 0;
while (1) {
cin >> a[count++];
if (getchar() == '\n') break; //跟以往遇到的,输入一串数字之前会先输入这一串数字的个数不同,这里没有个数
} //不知道这里有没有更好的办法
solve(a, count);
return 0;
}