题解 | #牛牛取石子#
牛牛的构造
https://ac.nowcoder.com/acm/problem/247579
题目描述
牛牛和牛妹在玩游戏,他们的游戏规则是这样的:
一共有两堆石子,第一堆有 a 个,第二堆有 b 个,牛牛和牛妹轮流取石子,牛牛先手,每次取石子的时候只能从以下 2 种方案种挑一种来取(对于选择的方案数必须保证当前石子 ≥ 取的石子个数才能取):
- 第一堆取 1 个,第二堆取 2 个
- 第一堆取 2 个,第二堆取 1 个
谁先无法取石子,谁就输了。假设牛牛和牛妹都很聪明,请问谁会获胜?
思路【对称策略(模仿棋)】
可以发现这两种操作是“对称”的,它们相加的和都为3.
如果先手选操作1,后手选操作2;若先手选操作2,后手选操作1;
那么相当于每两次为一轮,使两堆石子都减少3,每次先手想要改变“局面”,后手都使其回到与之前类似(指两堆石子相对大小)的情况。
举例找规律:
-
若开始为3和4,则一轮过后先手将面对0和1,无法操作,先手败。
-
若开始为5和9,则最后先手面对的情况为2和6,只要先手再进行操作2,则留给后手的石子变为了0和5,无法操作,后手败。
我们可以看出规律:
两堆石子数最少的那一个,若模3得零,则是一个“必败态”,谁面对这种情况就会输,因为后手只需进行对称操作,最终先手都会面对少的那堆变为0的情况而失败;相反,若少的那堆模3得1或得2,先手只需针对少的这堆选择操作使这堆为3的倍数,则将“必败态”留给了后手,先手赢。
但是,这题会产生特例!
考虑4和4:先手操作后,得到3和2,后手拿1和2,剩下2和0,先手败。
???!按照上面的分析,最小值4 模3得1,应该是“必胜态”呀,怎么会输?
当产生了特例的时候,我们便要考虑,是不是我们得分析出了差错,因为如果方法正确的话,是不会出现特例的。
其实上面的分析默认了一个条件:针对最小堆进行策略操作后不会改变原来两堆的相对大小,而当两堆相等时:
- 模3得1时:还是上面的例子,4和4,令另第一个4为较小值,先手要将其变为3的倍数,选择操作1,变为的3和2改变了一开始的“大小关系”,这时不是第一堆最小了,而是第二堆的2,2模3不为0,这对后手而言是“必胜态”。
- 模3得2时:例如5和5,令第一个5为较小值,进行操作2,变为3和4,仍是第一堆较小,未改变大小关系,先手赢。
至此,也便得到了正确代码:
#include<iostream>
#include<algorithm>
using namespace std;
long long x,y,s;
int main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int T;cin>>T;
while(T--){
cin>>x>>y;
int r=min(x,y)%3;
if(r){
if(r==1&&x==y)cout<<"niumei\n";
else cout<<"niuniu\n";
}
else cout<<"niumei\n";
}
return 0;
}