mini notes

競技プログラミングの解法メモを残していきます。

CPSCO2019 Session2 D - Two Piles(400)

D - Two Piles

概要

A枚のコインの山とB枚のコインの山がある。次のルールで2人ゲームを行い、最後に操作した人を勝者とする。先手勝ちならYes、後手勝ちならNoを出力せよ。

  • 2山のうちコインがある山を一つ選ぶ。その山のコインの枚数をX枚とする。
  • 各山から0枚以上のコインを取り去る。このとき取り去るコインの枚数はちょうどX枚とする。
制約

1 ≦ A, B ≦ 10^5

方針

2山のコインの数を(X, Y)と表記する。

(0, X)なら先手がX枚をまるまるとればよいので先手勝ち。

(X, Y)のとき、試しに(1, Z)にする手を考えてみる。(Z = Y-1 or X - 1)
すると後手が選べる手は(0, 1), (0, Z), (1, Z-1)の多くとも3通りだが、前者2つはすぐにその後先手に(0, 0)とされてしまうため選べない。よって(1, Z-1)を選択するしかない。
するとその後の先手は同じ理由で(1, Z-2)を選択するしかない。
よってゲームは(1, Z-1) → (1, Z-2) → … → (1, 0)→ (0, 0)と進行し、勝敗が決する。(1, Z)の勝敗は問題を解くカギとなりそう。

(1, Z)の勝敗を考えると(1, 0)なら先手勝ち、(1, 1)なら後手勝ち、(1, 2)なら先手勝ち…なので(1, 偶数)が先手勝ち、(1, 奇数)が後手勝ちとなる。

一般の(X, Y)に戻る。X, Yの偶奇で場合分けしてあげるとよさそう。
①(X, Y) = (偶数, 偶数):先手が(X - (X - 1), Y - 1) = (1, Y - 1)とすることで、(1, 奇数)の状態で後手に手を回せるため、先手勝ち
②(X, Y) = (奇数, 偶数):先手が(X - (X - 1), Y - 1) = (1, Y - 1)とすることで、(1, 奇数)の状態で後手に手を回せるため、先手勝ち
③(X, Y) = (偶数, 奇数):先手が(X - 1, Y - (Y - 1)) = (X - 1, 1)とすることで、(奇数, 1)の状態で後手に手を回せるため、先手勝ち
④(X, Y) = (奇数, 奇数):どのようにしても(偶数, 奇数)の状態で後手に手を回してしまうため、後手勝ち

解答

Submission #5383179 - CPSCO2019 Session2

#include <bits/stdc++.h>
#define rep(i,n) for(int i=(0);i<(n);i++)
 
using namespace std;
 
typedef long long ll;
 
int main()
{
	cin.tie(0);
	ios::sync_with_stdio(false);
 
	int A, B;
	cin >> A >> B;
 
	if(A % 2 == 1 && B % 2 == 1){
		cout << "No" << endl;
	}else{
		cout << "Yes" << endl;
	}
}