题意n个硬币反面朝上,抛m次,一次可以抛k枚硬币,问在最优得情况下正面朝上得概率
最优的情况 每次选的k枚硬币尽量都选反面朝上的
dp[i][j]表示 第i次抛硬币中j个正面朝上的概率,对于抛k枚硬币,c枚朝上的组合有 C(k,c)种
对于抛硬币正和反的概率都是0.5,所以抛k次概率为0.5^k
枚举跑K个正面朝上得个数c 则有C(K,C)个选择,
dp[i+1][x]=dp[i][j]*C(k,c)*0.5^k x为当前状态所有硬币正面朝上的个数)
当反面朝上得个数>=k则全部抛反面朝上得,即x=j+c
反之,会有一部分正面朝上得硬币和全部反面朝上得硬币一块跑,那么这时候没有被抛到得正面朝上得硬币的个数为n-k
那么这时候得枚举状态就是x=n-k+c
暑假做得一道题,忘记哪儿得了。
#include <bits/stdc++.h>
#define X 10005
#define inF 0x3f3f3f3f
#define PI 3.141592653589793238462643383
#define IO ios::sync_with_stdio(false),cin.tie(0), cout.tie(0);
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
typedef long long ll;
typedef unsigned long long Ull; //2^64
const int maxn = (int)1e6 + 10;
const int MOD = (int)1e9 + 7;
const ll inf = 9223372036854775807;
const int N = 47;
ll primer[maxn];
ll a[maxn];
int ans[maxn], num[maxn];
void ex_gcd(ll a, ll b, ll &d, ll &x, ll &y) { if (!b) { x = 1; y = 0; d = a; } else { ex_gcd(b, a%b, d, y, x); y -= x * (a / b); }; }
ll gcd(ll a, ll b) { return b ? gcd(b, a%b) : a; }
ll lcm(ll a, ll b) { return b / gcd(a, b)*a; }
ll inv_exgcd(ll a, ll m) { ll d, x, y;ex_gcd(a, m, d, x, y);return d == 1 ? (x + m) % m : -1; }
ll inv1(ll b) { return b == 1 ? 1 : (MOD - MOD / b)*inv1(MOD%b) % MOD; }
double C[200][200];
double p[200];
double dp[200][200];
int main()
{
IO;
int n, m, k;
C[0][0] = 1;
p[0] = 1.0;
for (int i = 1;i <= 150;++i)
{
p[i] = p[i - 1] * 0.5;
for (int j = 0;j <= i;++j)
{
C[i][j] =( j==0 ? 1: C[i - 1][j - 1] + C[i - 1][j]);
}
}
int t;cin >> t;
while (t--) {
cin >> n >> m >> k;
//dp[i][j] i次j个在上
memset(dp,0,sizeof(dp));
dp[0][0] = 1;
for (int i = 0;i < m;++i)
{
for (int j = 0;j <= n;++j)
{//cout<<1<<endl;
for (int c = 0;c <= k;++c)
{
if (n - j >= k) dp[i + 1][j + c] += dp[i][j] * C[k][c] * p[k];//+=是在上一个状态转移过来得到
else dp[i + 1][n - k + c] += dp[i][j] * C[k][c] * p[k];
}
}
}
double ans = 0.0;
for (int i = 0;i <= n;++i)
{
ans += dp[m][i] * i;
}
printf("%.3lf\n", ans);
}
return 0;
}