Atcoder-dp_j 题解

题目传送门

一道 dp 题……

发现以前课上讲的题能水题解。

dp 之前,我们需要明确以下几个东西:

状态的表示状态转移方程边界条件答案的表示

状态的表示

dpi,j,kdp_{i,j,k} 表示当有 33 个寿司的盘子还剩 ii 个,有 22 个寿司的盘子还剩 jj 个,有 11 个寿司的盘子还剩 kk 个时,吃完所有寿司操作次数的期望。

状态转移方程

i>0i>0 时:

dpi,j,k=dpi,j,k+dpi1,j+1,k×i÷(i+j+k)dp_{i,j,k}=dp_{i,j,k}+dp_{i-1,j+1,k}\times i\div (i+j+k)

j>0j>0 时:

dpi,j,k=dpi,j,k+dpi,j1,k+1×j÷(i+j+k)dp_{i,j,k}=dp_{i,j,k}+dp_{i,j-1,k+1}\times j\div (i+j+k)

k>0k>0 时:

dpi,j,k=dpi,j,k+dpi,j,k1×k÷(i+j+k)dp_{i,j,k}=dp_{i,j,k}+dp_{i,j,k-1}\times k\div (i+j+k)

(i+j+k)>0(i+j+k)>0 时:

dpi,j,k=dpi,j,k+n÷(i+j+k)dp_{i,j,k}=dp_{i,j,k}+n\div (i+j+k)

边界条件

dp0,0,0=0dp_{0,0,0}=0

答案的表示

dpcnt3,cnt2,cnt1dp_{cnt_3,cnt_2,cnt_1}

其中,cnticnt_i 表示有 ii 个寿司的盘子数量。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <bits/stdc++.h>
#define ll long long
#define INF 1e9
using namespace std;
int n;
int cnt[4];
double dp[305][305][305];
int main() {
ios :: sync_with_stdio(0);
cin >> n;
for (int i = 1; i <= n; i++) {
int x;
cin >> x;
cnt[x]++;
}
for (int i = 0; i <= cnt[3]; i++) {
for (int j = 0; j <= cnt[2] + cnt[3]; j++) {
for (int k = 0; k <= cnt[1] + cnt[2] + cnt[3]; k++) {
if (i == 0 and j == 0 and k == 0) continue;
if (i > 0) dp[i][j][k] += dp[i - 1][j + 1][k] * i / (i + j + k);
if (j > 0) dp[i][j][k] += dp[i][j - 1][k + 1] * j / (i + j + k);
if (k > 0) dp[i][j][k] += dp[i][j][k - 1] * k / (i + j + k);
dp[i][j][k] += 1.0 * n / (i + j + k);
}
}
}
printf("%.10lf", dp[cnt[3]][cnt[2]][cnt[1]]);
return 0;
}