【bzoj4147】 [AMPPZ2014]Euclidean Nim

9 篇文章 0 订阅
5 篇文章 0 订阅

这题不错啊。。。
E操作时,若n>p则任意取p的倍数,否则+p
P操作时同理。
问最终谁会取完。

exciting!推了三节数学课(雾)!

首先可以打表看看规律……然而并没有什么卵用
注意到标题是Euclidean Nim,猜测这题和Euclid肯定有关系(斜眼),然后可以尝试用扩欧手动模拟一下,胡乱搞搞。

画出几十棵博弈树后就可以大概猜出结果肯定和n,p,q的大小关系有关

以下来推结论。

首先无解的情况只有一种,就是 gcd(p,q)n ,这个可以通过扩欧 ax+by=d 来理解,这个方程无解当且仅当 gcd(x,y)d

那么对于别的情况一定有 gcd(p,q)n ,在一开始把 p,q,n 都除掉 gcd(p,q) 也不会影响结果。


Statu  0
显然当 p==q 时必有 p==1
故此时 (p,q,n) 为必胜态


Status  1
p>n,p>q
此时状态 (p,q,n) 只能转移到 (q,p,n+p) ,因为p只能往上加
接着只需要转移成 (p,q,(n+p) mod q) ,此时 (n+p) mod q<p,q<p ,故p仍然只能往上加
如此反复p永远没有取走石子的机会,则q必定会取完所有石子。


Status  2
np>q
此时 (p,q,n) 比较复杂
首先如果转移到了某个状态 (q,p,x) ,其中 xq ,那么q可以将其转移成 (p,q,x mod q) ,变成了Status 1,p必败。
因此十分机智的p是肯定不会将现在状态变成那样的。
为了方便讨论,p取到了 n mod p ,当然必须要有 n mod p<q 否则还是得挂。这个时候变成了 (q,p,x) ,其中 x=n mod p,x<q ,傲娇的p和q开始了这样 (p,q,x+q)>(q,p,x+qp)>(p,q,x+qp+q)>(q,p,x+qp+qp) ……若p要胜,则需要有 (nq)(n mod p)
故此时 (p,q,n) 为必胜态当且仅当 (nq)(n mod p) && n mod p<q


Status 3
p<n,p<q
(p,q,n)(q,p,n mod p) ,此时 q>p,q>n mod p ,q必败,则原状态必胜。


Status 4
q>p>n
(p,q,n)(q,p,n+p)
n+pq ,则转到Status 2
否则即为Status 1,必败,原状态必胜。


#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define stop(x) return puts(x) , 0

inline int rd() {
    char c = getchar();
    while (!isdigit(c)) c = getchar() ; int x = c - '0';
    while (isdigit(c = getchar())) x = x * 10 + c - '0';
    return x;
}

int gcd(int a , int b) { return b ? gcd(b , a % b) : a ; }

bool check(int p , int q , int n) {
    n %= p;
    return n < q && n % (p - q) == 0;
}

int p , q , n;

int solve() {
    p = rd() , q = rd() , n = rd();
    int g = gcd(p , q);
    if (n % g)
        stop("R");
    p /= g , q /= g , n /= g;
    if (p == q)
        stop("E"); // status 0
    if (p > n) {
        if (p > q)
            stop("P"); // status 1
        else if (q > p) { // status 4
            if (n + p < q)
                stop("E"); //4 - section 2
            else
                stop(check(q , p , n + p) ? "P" : "E"); //4 - section 1
        }
    } else {
        if (p > q)
            stop(check(p , q , n) ? "E" : "P"); // status 2
        else
            stop("E"); // status 3
    }
}

int main() {
    #ifndef ONLINE_JUDGE
    //  freopen("data.txt" , "r" , stdin);
    #endif
    int T = rd();
    while (T --)
        solve();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值