結果
| 問題 |
No.3120 Lower Nim
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2025-04-20 19:30:12 |
| 言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
TLE
|
| 実行時間 | - |
| コード長 | 3,154 bytes |
| コンパイル時間 | 2,200 ms |
| コンパイル使用メモリ | 195,532 KB |
| 実行使用メモリ | 25,972 KB |
| 平均クエリ数 | 114.23 |
| 最終ジャッジ日時 | 2025-04-20 19:30:20 |
| 合計ジャッジ時間 | 7,203 ms |
|
ジャッジサーバーID (参考情報) |
judge1 / judge5 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | -- * 1 |
| other | AC * 6 TLE * 1 -- * 36 |
ソースコード
#include <bits/stdc++.h>
using namespace std;
using int64 = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N; // 山の数
cin >> N;
vector<int> A(N); // 各山
for (int &v : A) cin >> v;
auto next_pow2 = [](int64 k) {
int64 p = 1;
while (p <= k) p <<= 1;
return p; // k をこえる最小の 2 のべき
};
auto nim_xor = [&](int64 P)->int64 {
int64 x = 0;
for (int v : A) x ^= (v % P);
return x;
};
// ---------- 先攻/後攻を決める ----------
int64 hugeK = (int64)1e18; // 10^100 と同じ扱い
int64 first_xor = nim_xor(next_pow2(hugeK)); // = 通常の xor
bool iamFirst = (first_xor != 0);
cout << (iamFirst ? "First" : "Second") << '\n' << flush;
int64 K = hugeK; // 直前手の取り量(初手は∞)
while (true) {
if (!iamFirst) { // 先手でなければ相手の着手を読む
int idx, x; // 1‑based
if (!(cin >> idx >> x)) return 0;
A[idx-1] -= x; // 山を更新
K = x; // 新しい制限
int ret; cin >> ret; // Interactor の OK (=0)
if (ret) return 0;
}
// ---------- 自分の手を探す ----------
int64 P = next_pow2(K);
int64 g = nim_xor(P);
int sel = -1, take = -1;
if (g != 0) {
// 「勝ち局面」なので取れる手を探す
for (int i = 0; i < N && sel==-1; ++i) {
int64 r = A[i] % P; // その山のブロック内値
// 取り量を 1..min(A[i],K) で全探索(十分小さい)
int upper = min<int64>(A[i], K);
for (int x = 1; x <= upper; ++x) {
int64 newK = x;
int64 P2 = next_pow2(newK);
int64 nxor = 0;
for (int j = 0; j < N; ++j) {
int64 val = (j==i) ? (A[j]-x) : A[j];
nxor ^= (val % P2);
}
if (nxor == 0) { // 相手を負け局面へ
sel = i;
take = x;
break;
}
}
}
}
if (sel == -1) { // g==0 か「探索で見つからず」
// K=1 ゲーム(偶奇ゲーム)に帰着させる
for (int i = 0; i < N; ++i)
if (A[i] && 1 <= K) { // 常に成立
sel = i;
take = 1;
break;
}
}
// ----------- 出力して山を更新 -------------
cout << (sel + 1) << ' ' << take << '\n' << flush;
A[sel] -= take;
K = take;
int ret; cin >> ret;
if (ret) return 0; // interactor が 0 以外なら終了
iamFirst = false; // 2 手目以降は常に後手扱い
}
}