1. 程式人生 > >“東信杯”廣西大學第一屆程式設計競賽(同步賽)D、數論只會GCD 【博弈 分類討論】

“東信杯”廣西大學第一屆程式設計競賽(同步賽)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