n個硬幣反面朝上,拋m次,一次可以拋k枚硬幣,正面朝上得概率
阿新 • • 發佈:2019-01-10
題意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; }