“东信杯”广西大学第一届程序设计竞赛(同步赛)D、数论只会GCD 【博弈 分类讨论】

传送门:https://ac.nowcoder.com/acm/contest/283/D

题目描述 

小西买了一堆肥宅快乐水和肥宅快乐茶,准备和室友比谁更肥宅。
快乐水有A瓶,快乐茶B瓶。
小西和室友的规则是这样的:
1. 小西先手,轮流到每个人的回合,每个回合只能喝剩余数量较多的饮料
2. 满足规则1的同时,每次只能喝另一种饮料剩余数量的正整数倍
3. 满足1、2的同时,不能超额喝饮料,也就是说剩下2瓶的时候不能喝大于2瓶的数量。
4. 每个人在自己的回合如果能喝完剩下的其中一种饮料,那么就获得胜利。
例如A=10,B=2。
小西只能喝快乐水,且只能喝2/4/6/8/10瓶快乐水。小西可以喝10瓶快乐水直接获得胜利。
 
小西和室友都是肥宅,所以他们都会才采取为了胜利最优的行动。
现在请你判断小西是否能赢得胜利。

输入描述:

第一行输入一个整数T,表示有T组数据
接下来T行,每行为一组数据,每行有两个正整数表示A和B的初始数量
 

输出描述:

对于每组数据,若小西可以获得胜利则输出一行“wula”,否则输出一行“mmp”,不需要输出引号
示例1

输入

复制
2
20 18
10 4

输出

复制
mmp
wula

题意概括:如题

解题思路:

模拟一遍,博弈的规律很清晰。

处理一下保证 A > B,并且两者除掉GCD缩小范围,最后得出结果是等价的(两者除以相同倍数,和每次做减法是减少相同的数,对最后能否整除没有影响)。

递归判断 cheak(A, B,cnt)是先手赢或是后手赢,cnt用于记录奇偶性(由当前结果回溯到最初的结果)

①如果当前 A%B == 0 先手赢

②如果当前 A/B >= 2 先手赢  (因为我存在至少两种选择,里面必有一种是失败的,而另外一种肯定是胜利的)

  为什么呢?

    如果A/B == 2 ,我们至少拥有减 2 个 B的权利,如果我减一个B最后导致我失败了对手胜利了,那我肯定减两个B,就相当于我通过多减一个B跳过了一步,而我成为了成功的那个对手。

  如果减一个B成功了,那就成功啦

    如果 A/B > 2, 我们其实还是回到上面的结论,减一个或减两个,其余的都是附加在这一个或者两个上的,保证奇偶性即可。

③以上两种情况不满足说明当前状态无法判断谁会获胜,需要做一次减法 A-B,递归 cheak( A-B,B,++cnt)或者check(B,A-B,++cnt)判断接下来那个会获胜,因为记录了奇偶性,最后可以回溯到最初状态。

AC code:

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 #include <algorithm>
 5 #define LL long long
 6 using namespace std;
 7 LL a, b;
 8  
 9 LL GCD(LL a, LL b)
10 {
11     if(b == 0) return a;
12     return GCD(b, a%b);
13 }
14  
15 bool check(LL A, LL B, LL cnt)
16 {
17     LL gg = GCD(A, B);
18     A = A/gg;
19     B = B/gg;
20     LL t = A/B;
21     if(A%B == 0) {
22         if(cnt%2LL) return true;
23         else return false;
24     }
25     else if(t >= 2){
26  
27             if(cnt%2LL) return true;
28             else return false;
29  
30     }
31     else{
32         if(B%(A-B) == 0) {
33                 if(cnt%2LL)return false;
34                 else return true;
35         }
36         else{
37             if(B > (A-B))   return check(B, (A-B), ++cnt);
38             else return check((A-B), B, ++cnt);
39         }
40     }
41     return true;
42 }
43  
44 int main()
45 {
46     int T_case;
47     LL tt, cnt = 1LL;
48     LL G;
49     scanf("%d", &T_case);
50     while(T_case--){
51         cnt = 1LL;
52         scanf("%lld %lld", &a, &b);
53         if(a < b) swap(a, b);
54         if(a%b == 0) puts("wula");
55         else{
56             G = GCD(a, b);
57             a = a/G;
58             b = b/G;
59             if(check(a, b, 1LL)) puts("wula");
60             else puts("mmp");
61         }
62     }
63     return 0;
64 }
View Code
原文地址:https://www.cnblogs.com/ymzjj/p/10029029.html