这题看了别人的题解才知道真正意思,哈哈哈,忍不住分享一下我的理解方式: n个什么东西站立在牛头山和云台山之间的寺里(好像可以理解为雕像?)。n个雕像矗立在牛头山和云台山之间的寺里,然而随着时间流逝,只剩下标号为a,b的两座雕像仍然矗立。俩猴子,(...monk=monkey)叫Y..和I..决定重铸雕像群的辉煌。俩候轮流建雕像,Y..先来。每一轮每猴只能重建一座雕像,标号为i,而且在已有的雕像中,找两个标号为j,k,那么i = j + k或者 i = j - k。每个标号的雕像只能重建一次。轮到谁,谁不能建新雕像谁就输,也就是说谁建最后一座雕像谁就赢(当然这里第一个样例就给出了这种等价唯一的不妥之处)。
大佬的优雅翻译以及牛逼题解:传送门
解题为主嘛,虽然意思和意境有所偏差,但是题意基本get到了。初见这题,又是俩人掐架,又是俩人轮流一人先,不禁让我想起了前几天刚补的一道题:B2-B - Breaking Branches(博弈)
不禁惊呼一声,卧槽,真的好像。但是这题好像又更复杂,什么i = j - k || i = j + k,俩人又是每次都会做出最明智的选择(折树枝那个好像也有这句话),我现在(写这篇文)的理解就是做出最明智的选择 = 战满所有回合,所有的可能他俩都会涉及到。当时做这题的时候,有点懵,但是有了折树枝那题的先例,我就在想是不是只需要找出所有的修到标号的可能,然后再判断奇偶数就能得出答案了?大胆猜测,小心验证。我试了几个例子,好像是这么一回事。那么接下来的任务就是怎么找出所有可能修到的标号呢?还是看样例,慢慢地,矛头就指向一个东西——最大公约数。修的总数=原总数/gcd(a,b) - 2。当然我还是猜嘛,然后就代码实现。涉及到的知识点就是求俩数的最大公约数——辗转相除法。我就是笨比,场上其实不太会,还是搜的原理。。。然后感觉可以用递归写,但是又有点迷糊,就用while写的……代码敲完,一跑样例,全过。然后信心大增,就直接交了,直接过了。哈哈哈哈,心情贼爽!
场上写的码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <cmath>
using namespace std;
int gcd(int a, int b) {
int t;
if(a < b)
swap(a, b);
while(a % b != 0) {
t = a;
a = b;
b = t % b;
}
return b;
}
int main() {
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
int a, b, t, n;
int cnt = 0;
cin >> t;
while(t--) {
cnt++;
cin >> n >> a >> b;
cout << "Case #" << cnt << ": ";
if(((n/gcd(a,b))-2)%2)
cout << "Yuwgna" << endl;
else
cout << "Iaka" << endl;
}
// cout << gcd(a, b);
return 0;
}
然后我发现我写的gcd函数真就是原理直接照搬。。。
两个点:
1.其实不用判断大小关系,大不了就多进行一次循环的事;
2.想要的递归代码:
int gcd(int a,int b) {
return b?gcd(b,a%b):a;
}
换上程序能更简洁一些
附一些额外的东西:
1.这题规律的证明
2.裴蜀定理
3.递归函数