Codeforces Round #114 (Div. 1) C : Wizards and Numbers
問題概要
ふたつの数A,B(A<=B)に対して
- BからA^k(k>0)を引く。
- BをB%Aで置き換える。
のいずれかの操作を施す。どちらかが0の状態で自分の番になったら負ける。勝つのが先手か後手か判定する問題。A,B<10^18、テストケース数10^4。
解法
(B%A, A)が負けの状態であるとき、その状態に遷移できるので(A,B)は勝ちである。(B%A, A)が勝ちの状態であるとき、どちらのプレイヤーも(B%A, A)に遷移しないようにしなければならない。
したがってBからAのべきを引くしかないのだが、BがAより小さくなったらそれは必ず(B%A, A)という状態である。何故ならBから引く数は必ずAの倍数だからである。
結局、BからA^k(k>0)を何回引くことができるか、というゲームに帰着される。これはk>=0であればSRM PotateGameなどで見た有名問題そのものである。この問題はk>0となっているが、BをB/A+1で考えればk>=0で考えるのと同じことになる。したがってB/A+1をk+1で割った余りを見てやればよい。
こんなん言われてやっと気づくレベル…。
acceptされたコード
#include <cstdio> #include <iostream> #include <algorithm> using namespace std; typedef long long int64; int64 A, B; void init(){ cin >> A >> B; } bool rec(int64 A, int64 B){ if(A == 0 || B == 0){ return false; } if(A > B){ swap(A, B); } if(!rec(B%A, A)){ return true; } return ( (B/A)%(A+1) )%2 == 0; } int main(){ int T; cin >> T; for(;T--;){ init(); puts(rec(A, B) ? "First" : "Second"); } return 0; }