zoukankan      html  css  js  c++  java
  • “东信杯”广西大学第一届程序设计竞赛(同步赛)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
  • 相关阅读:
    linux内核主要模块图
    Linux0.11内核几种地址(逻辑地址、线性地址、物理地址)的含义
    Linux一个多线程的面试题
    进程的用户栈和内核栈
    Ubuntu 下安装LXR(linux源代码阅读工具)
    Linux多线程与同步
    实模式与保护模式
    Linux下的多线程编程
    寒假Day34:HTML表单+多媒体+框架
    寒假Day34:HDU1514Free Candies记忆化搜索
  • 原文地址:https://www.cnblogs.com/ymzjj/p/10029029.html
Copyright © 2011-2022 走看看