結果
問題 |
No.3055 Simple Chicken Game
|
ユーザー |
![]() |
提出日時 | 2025-01-25 19:08:02 |
言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
結果 |
TLE
|
実行時間 | - |
コード長 | 3,761 bytes |
コンパイル時間 | 1,971 ms |
コンパイル使用メモリ | 96,924 KB |
実行使用メモリ | 10,624 KB |
最終ジャッジ日時 | 2025-02-05 00:28:29 |
合計ジャッジ時間 | 44,116 ms |
ジャッジサーバーID (参考情報) |
judge2 / judge1 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 2 |
other | AC * 17 TLE * 13 |
ソースコード
#include <cassert> #include <iostream> #include <vector> #include <atcoder/modint> using mint = atcoder::modint; // プレイヤー player の操作前を考える。 // stay グループにいるプレイヤーの中で最も順位の低いプレイヤーの順位の期待値 mint StayPlayer( const int player, const int stay, const int bottom, const int n) { if (player == n) return n - bottom; mint ans_0 = 0, ans_1 = 0; // どちらでもよいケースのためだけにメモしておく if (stay <= bottom) ans_0 = StayPlayer(player + 1, stay + 1, bottom, n) - 1; if (stay >= bottom) { ans_1 += StayPlayer(player + 1, stay, bottom, n); // 表 ans_1 += StayPlayer(player + 1, stay, bottom + 1, n); // 裏 ans_1 /= 2; } // プレイヤー player は操作を行った方が最適 if (stay < bottom) return ans_0; // プレイヤー player は操作を行わない方が最適 if (stay > bottom) return ans_1; return (ans_0 + ans_1) / 2; // どちらでもよい } // プレイヤー player の操作前を考える。 // bottom グループにいるプレイヤーの中で最も順位の低いプレイヤーの順位の期待値 mint BottomPlayer( const int player, const int stay, const int bottom, const int n) { if (player == n) return n; mint ans_0 = 0, ans_1 = 0; // どちらでもよいケースのためだけにメモしておく if (stay <= bottom) ans_0 = BottomPlayer(player + 1, stay + 1, bottom, n); if (stay >= bottom) { ans_1 += BottomPlayer(player + 1, stay, bottom, n); // 表 ans_1 += BottomPlayer(player + 1, stay, bottom + 1, n) - 1; // 裏 ans_1 /= 2; } // プレイヤー player は操作を行わない方が最適 if (stay < bottom) return ans_0; // プレイヤー player は操作を行った方が最適 if (stay > bottom) return ans_1; return (ans_0 + ans_1) / 2; // どちらでもよい } // プレイヤーの最適手は以下のみに依存することを前提としている。 // - 以前に操作を行わなかったプレイヤーの人数 // - 以前に操作を行って裏が出たプレイヤーの人数 int main() { constexpr int kMaxN = 3000, kMinP = 100000000, kMaxP = 1000000000; int n, p; std::cin >> n >> p; assert(1 <= n && n <= kMaxN); assert(kMinP <= p && p <= kMaxP); mint::set_mod(p); std::vector dp(1, std::vector{mint::raw(1)}); for (int player = 0; player < n; ++player) { mint ans = 0; std::vector nxt(player + 2, std::vector(player + 2, mint())); // 操作しなかったプレイヤー for (int stay = 0; stay <= player; ++stay) { // 下位が確定しているプレイヤー for (int behind = 0; stay + behind <= player; ++behind) { const mint prob = dp[stay][behind]; if (prob == 0) continue; mint rank_0 = 0, rank_1 = 0; if (stay <= behind) { rank_0 = StayPlayer(player + 1, stay + 1, behind, n); } if (stay >= behind) { rank_1 += player - (stay + behind) + 1; // 表 rank_1 += BottomPlayer(player + 1, stay, behind + 1, n); // 裏 rank_1 /= 2; } if (stay < behind) { ans += rank_0 * prob; nxt[stay + 1][behind] += prob; } else if (stay > behind) { ans += rank_1 * prob; nxt[stay][behind] += prob / 2; nxt[stay][behind + 1] += prob / 2; } else { assert(rank_0 == rank_1); ans += rank_0 * prob; // どちらでもよい nxt[stay + 1][behind] += prob / 2; nxt[stay][behind] += prob / 4; nxt[stay][behind + 1] += prob / 4; } } } dp.swap(nxt); std::cout << ans.val() << " \n"[player + 1 == n]; } return 0; }