Official
H - Remove Pairs Editorial
by
H - Remove Pairs Editorial
by
MtSaka
場にあるカードの集合としてありえるものは \(2^{N}\) 通りです。 この全ての場合について、それが先手が操作をする直前の時に場にあるカードの集合であったときに先手が勝つか後手が勝つか判定することができれば良いです。
これはいわゆる bitDP というテクニックを利用して解くことができます。
\(dp[S]\) = 場にあるカードの集合が \(S\) の状態で先手から始まる時に先手が勝つことができる時 true
そうでない時 false
とし、遷移は以下の通りです。
カードの集合 \(S\) について、ある \(i,j \in S\) で\(A_i=A_j\) または \(B_i=B_j\) を満たす \(i,j\) について \(dp[S \setminus \{i,j\}]\) が
false
である時に \(dp[S]\) はtrue
、それ以外の場合では \(dp[S]\) はfalse
最終的に答えは、\(S=\{1,2,\ldots,N\}\) の時の \(dp[S]\)が true
である時に Takahashi
、false
である時に Aoki
となります。
状態数は \(O(2^{N})\) で遷移は \(O(N^{2})\) であるため、計算量は \(O(2^{N} {N}^{2})\) となり、十分高速です。
実装例(C++):
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
vector<int> a(n), b(n);
for (int i = 0; i < n; ++i)
cin >> a[i] >> b[i];
vector<int> dp(1 << n, -1);
dp[0] = 0;
for (int i = 1; i < (1 << n); ++i) {
bool f = false;
for (int j = 0; j < n; ++j)
for (int k = j + 1; k < n; ++k) {
if (((i >> j) & 1) && ((i >> k) & 1)) {
if ((a[j] == a[k] || b[j] == b[k]) && dp[i ^ (1 << j) ^ (1 << k)] == 0) {
f = true;
}
}
}
dp[i] = f;
}
cout << (dp.back() ? "Takahashi" : "Aoki") << endl;
}
posted:
last update: