题目传送门
一道 dp 题……
发现以前课上讲的题能水题解。
在 dp
之前,我们需要明确以下几个东西:
状态的表示,状态转移方程,边界条件跟答案的表示。
状态的表示
dpi,j,k 表示当有 3 个寿司的盘子还剩 i 个,有 2 个寿司的盘子还剩 j 个,有 1 个寿司的盘子还剩 k 个时,吃完所有寿司操作次数的期望。
状态转移方程
当 i>0 时:
dpi,j,k=dpi,j,k+dpi−1,j+1,k×i÷(i+j+k)
当 j>0 时:
dpi,j,k=dpi,j,k+dpi,j−1,k+1×j÷(i+j+k)
当 k>0 时:
dpi,j,k=dpi,j,k+dpi,j,k−1×k÷(i+j+k)
当 (i+j+k)>0 时:
dpi,j,k=dpi,j,k+n÷(i+j+k)
边界条件
dp0,0,0=0
答案的表示
dpcnt3,cnt2,cnt1
其中,cnti 表示有 i 个寿司的盘子数量。
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; }
|