Sushi,(期望 dp,概率dp,线性dp )
Sushi - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
Problem Statement
There are N dishes, numbered ,2,…,N. Initially, for each i (1≤i≤N), Dish i has ai (1≤ai≤3) pieces of sushi on it.
Taro will perform the following operation repeatedly until all the pieces of sushi are eaten:
- Roll a die that shows the numbers 1,2,…,N with equal probabilities, and let i be the outcome. If there are some pieces of sushi on Dish i, eat one of them; if there is none, do nothing.
Find the expected number of times the operation is performed before all the pieces of sushi are eaten.
Constraints
- All values in input are integers.
- 1≤N≤300
- 1≤ai≤3
Input
Input is given from Standard Input in the following format:
N a1 a2 ……aN
Output
Print the expected number of times the operation is performed before all the pieces of sushi are eaten. The output is considered correct when the relative difference is not greater than 10−910−9.
Sample 1
Inputcopy | Outputcopy |
---|---|
3 1 1 1 | 5.5 |
The expected number of operations before the first piece of sushi is eaten, is 11. After that, the expected number of operations before the second sushi is eaten, is 1.51.5. After that, the expected number of operations before the third sushi is eaten, is 33. Thus, the expected total number of operations is 1+1.5+3=5.51+1.5+3=5.5.
Sample 2
Inputcopy | Outputcopy |
---|---|
1 3 | 3 |
Outputs such as 3.00
, 3.000000003
and 2.999999997
will also be accepted.
Sample 3
Inputcopy | Outputcopy |
---|---|
2 1 2 | 4.5 |
Sample 4
Inputcopy | Outputcopy |
---|---|
10 1 3 2 3 3 2 3 2 1 3 | 54.48064457488221 |
Sponsor
解析:
题解 AT4531 Sushi - 触情离殇 的博客 - 洛谷博客 (luogu.com.cn)
由于每个盘子最多只有3个寿司,所以我们可以以这个位突破口
状态划分:不重不漏,将状态转移所依据的状态体现出来;
f[i][j][k],表示:拿走1个寿司的盘子有 i 个,拿走2个寿司的盘子有 j 个,拿走3个寿司的盘子有 k 个的最大步数
状态转移:当前状态
有 (n-i-j-k)/n 的概率从选中空盘子,即从状态 f[i][j][k] 转移过来
有 i/n 的概率从选中有1个寿司的盘子,即从状态 f[i-1][j][k] 转移过来
有 j/n 的概率从选中有2个寿司的盘子,即从状态 f[i+1][j-1][k] 转移过来
有 k/n 的概率从选中有3个寿司的盘子,即从状态 f[i][j+1][k-1] 转移过来
所以状态转移方程:
f[i][j][k]=1+f[i][j][k]*(n-i-j-k)/n+f[i-1][j][k]*i/n+f[i+1][j-1][k]*j/n+f[i][j+1][k-1]*k/n;
化简得:
f[i][j][k]=n/(i+j+k)+f[i-1][j][k]*i/(i+j+k)+f[i+1][j-1][k]*j/(i+j+k)+f[i][j+1][k-1]*k/(i+j+k);
#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<math.h>
#include<map>
using namespace std;
typedef long long LL;
const int N = 3e2 + 5;
int n;
int cnt[4];
double f[N][N][N];
int main() {
cin >> n;
for (int i = 1,a; i <= n; i++) {
scanf("%d", &a);
cnt[a]++;
}
//cout << cnt[1] << " " << cnt[2] << " " << cnt[3] << endl;
for (int k = 0; k <= n; k++) {
for (int j = 0; j <= n; j++) {
for (int i = 0; i <= n; i++) {
//cout << i << endl;
if(i||j||k)
f[i][j][k] += (double)n / (i + j + k);
if (i)f[i][j][k] += (double)i / (i + j + k) * f[i - 1][j][k];
if (j)f[i][j][k] += (double)j / (i + j + k) * f[i + 1][j - 1][k];
if (k)f[i][j][k] += (double)k / (i + j + k) * f[i][j + 1][k - 1];
}
}
}
printf("%.10lf\n", f[cnt[1]][cnt[2]][cnt[3]]);
return 0;
}