AtCoder

ABC360 E問題(Random Swaps of Balls)を解く

AtCoder_ABC360_E

AtCoder が提供しているABC(AtCoder Beginner Contest)360 E問題をC++とPythonで解いてみました。ABC360は、2024年6月30日21:00に実施されました。

AtCoder の紹介はこちらに、プログラミングの方針はこちらに記事があります。

E問題 Random Swaps of Balls(Difficulty : 1249)

問題の詳細は、リンク先をご覧ください。

ABC360 E問題 Random Swaps of Balls

黒いボールが一番左にある確率を求めます。AtCoder Problems による Difficulty は 1249 でした。

解答案

コンテスト中に解くことができませんでした。公式解説を参考にコーディングしました。

C++ プログラム例(ABC360E)

公式解説の式を、そのままコーディングしました。dp[i] は、i回目の操作の後に一番左に黒がある確率です。k回の操作後に2番目以降に黒がある確率は、一律 $(1 – dp_k)/(N – 1)$ となります。期待値は、等差数列の和の公式を使って、

$$dp_k + 2 \times \frac{1 – dp_k}{N – 1} + 3 \times \frac{1 – dp_k}{N – 1} \cdots N \times \frac{1 – dp_k}{N – 1}$$

$$ = dp_k + \frac{(N + 2)(N – 1)}{2} \times \frac{1 – dp_k}{N – 1} = \frac{(N + 2)}{2} \times (1 – dp_k)$$

となります。以下が、C++プログラムです。

#include <bits/stdc++.h>
#include <atcoder/modint>
using namespace std;
using namespace atcoder;

typedef modint998244353 mint;

int main()
{
	int n, k;
	cin >> n >> k;
	mint mint_n = (mint)n;

	vector<mint> dp(k + 1);
	dp[0] = mint(1);
	mint p = (mint)2 * (mint_n - 1) / (mint_n * mint_n);
	mint q = (mint)2 / (mint_n * mint_n);
	for (int i = 0; i < k; ++i) {
		dp[i + 1] = (1 - p) * dp[i] + q * (1 - dp[i]);
	}

	mint result = dp[k];
	result += (mint_n + 2) * (1 - dp[k]) / 2;
	cout << result.val() << endl;

	return 0;
}

AC(Accepted=正しいプログラム)と判定されました。

Python プログラム例(ABC360E)

Python版も基本的な考え方は同じです。以下がプログラムです。

"""AtCoder Beginner Contest 360 E"""
MOD = 998244353
n, k = map(int, input().split())

inv_n = pow(n, MOD - 2, MOD)
inv_2 = pow(2, MOD - 2, MOD)

dp = [0] * (k + 1)
dp[0] = 1
p = 2 * (n - 1) * inv_n * inv_n % MOD
q = 2 * inv_n * inv_n % MOD
for i in range(k):
    dp[i + 1] = (1 + MOD - p) * dp[i] + q * (1 + MOD - dp[i])
    dp[i + 1] %= MOD

result = dp[k]
result += (n + 2) * (1 + MOD - dp[k]) * inv_2
result %= MOD
print(result)

こちらも「AC」と判定されました。

最後に

確率DPは、慣れてきた気がしていましたが、まだまだでした。

引き続き ABC の問題を紹介していきます。

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA