結果
| 問題 |
No.3120 Lower Nim
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2025-04-20 19:35:17 |
| 言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
WA
|
| 実行時間 | - |
| コード長 | 3,042 bytes |
| コンパイル時間 | 2,087 ms |
| コンパイル使用メモリ | 195,768 KB |
| 実行使用メモリ | 25,972 KB |
| 平均クエリ数 | 2330.34 |
| 最終ジャッジ日時 | 2025-04-20 19:35:29 |
| 合計ジャッジ時間 | 10,429 ms |
|
ジャッジサーバーID (参考情報) |
judge5 / judge2 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 1 |
| other | AC * 41 WA * 2 |
ソースコード
#include <bits/stdc++.h>
using namespace std;
using int64 = long long;
// k を超える最小の 2 の冪を返す
int64 next_pow2(int64 k) {
int64 p = 1;
while (p <= k) p <<= 1;
return p;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N;
cin >> N;
vector<int64> A(N);
for (int i = 0; i < N; i++) {
cin >> A[i];
}
// 初手用の大きな K (山の総数 <= 10^4 なので十分)
int64 K = (int64)1e18;
// 初回の P, mask, XOR を計算して先攻/後攻を決める
{
int64 P = next_pow2(K);
int64 mask = P - 1;
int64 g = 0;
for (int i = 0; i < N; i++) {
g ^= (A[i] & mask);
}
if (g != 0) {
cout << "First\n" << flush;
} else {
cout << "Second\n" << flush;
}
}
bool myTurn = false;
{
// 再度同じ XOR を計算して myTurn を初期化
int64 P = next_pow2(K);
int64 mask = P - 1;
int64 g = 0;
for (int i = 0; i < N; i++) g ^= (A[i] & mask);
myTurn = (g != 0);
}
// --- インタラクティブなやり取りループ ---
while (true) {
// (1) 相手の手を読む
if (!myTurn) {
int j;
int64 y;
if (!(cin >> j >> y)) return 0;
// 山 j から y を取られた
A[j - 1] -= y;
K = y;
int judge;
cin >> judge;
if (judge != 0) return 0;
}
// (2) 自分の手を決める (O(N + log K))
int64 P = next_pow2(K);
int64 mask = P - 1;
// 現局面の Nim XOR
int64 g = 0;
for (int i = 0; i < N; i++) {
g ^= (A[i] & mask);
}
int sel = -1;
int64 take = 0;
if (g != 0) {
// 勝ち局面 → 取り量 x は一意に決まる
// g の最上位ビットを取り出す
int shift = 63 - __builtin_clzll(g);
int64 hb = 1LL << shift;
for (int i = 0; i < N; i++) {
int64 r = A[i] & mask;
if (r & hb) {
// x = r - (r xor g)
sel = i;
take = r - (r ^ g);
break;
}
}
// (必ず見つかる)
}
if (sel == -1) {
// g==0 の負け局面なら,石 1 個だけ取るフォールバック
for (int i = 0; i < N; i++) {
if (A[i] > 0) {
sel = i;
take = 1;
break;
}
}
}
// (3) 出力→更新
cout << (sel + 1) << " " << take << "\n" << flush;
A[sel] -= take;
K = take;
int judge;
cin >> judge;
if (judge != 0) break;
// 2手目以降は常に後手として振る舞う
myTurn = false;
}
return 0;
}