結果
| 問題 |
No.3055 Simple Chicken Game
|
| コンテスト | |
| ユーザー |
emthrm
|
| 提出日時 | 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;
}
emthrm