https://codeforces.com/gym/101606/problem/F
题意
初始有n枚硬币正面朝下,一共要抛硬币m次,每次都是以最优的策略抛,问最后正面朝上的硬币的期望是多少。
1<=n,m<=400
题解
最优的策略即不到万不得已不会选已经是正面的硬币抛,一开始想的是用一个公式解出这题,其实这是很不现实的,因为总会以最优的策略抛,根本就没法用公式来代替,况且数据范围是400,组合数也算不下。
因为太少接触概率dp,所以根本看不出来。
dp[i][j]:
抛j
次有i
枚硬币朝上的概率。
i<n
:
dp[i+1][j+1] = dp[i][j]*0.5
dp[i][j+1] = dp[i][j]*0.5
i == n
dp[i][j+1] = dp[i][j]*0.5
dp[i-1][j+1] = dp[i][j]*0.5
因为一旦 i==n
那么策略就不一样了,不能用同一个转移方程。 这里最外层应该枚举j
,因为j
是有序的,总是会用到j-1
,为什么不能枚举i
呢,因为i-1
会在i
的时候更新,有后效性。
代码
#include <bits/stdc++.h>
using namespace std;
#define FOR0(a,b) for(int i = a; i < b; ++i)
#define FORE(a,b) for(int i = a; i <= b; ++i)
typedef long long ll;
typedef pair<int,int> pii;
const int maxn = 405;
int n,k;
double dp[maxn][maxn];
int main() {
scanf("%d%d", &n, &k);
dp[0][0] = 1;
for(int j = 0; j <= k; ++j) {
for(int i = 0; i <= n; ++i) {
if(i == n) {
dp[i-1][j+1] += dp[i][j]*0.5;
dp[i][j+1] += dp[i][j]*0.5;
} else {
dp[i+1][j+1] += dp[i][j]*0.5;
dp[i][j+1] += dp[i][j]*0.5;
//cout << i <<" " << j << " " << dp[i][j] <<" " << dp[i+1][j+1]<< endl;
}
}
}
double ans = 0;
for(int i = 1; i <= n; ++i)
ans += i*dp[i][k];
printf("%.8lf\n", ans);
return 0;
}