ACM-ICPC 2017 Asia Urumqi A - Coins 概率dp

题目链接
用dp[i][j]表示翻第i轮,有j个朝上,这题用往后推的方法比较好写。而不是在前面找。
然后用san[i][j]表示抛i个硬币,有j个向上的概率,注意这个概率跟那i个硬币原来是正是反没关系。

根据题目的要求,要尽量让向上的硬币多,所以每次尽量选朝下的硬币,但朝下的硬币可能不够,所以
dp里往后推的时候要分两种情况
1. 朝下硬币够k个,那么dp[i][j]*san[k+1][l+1]
2. 朝下硬币不够,要从朝上硬币里面借,因为它们本来就是朝上的,所以这次朝上硬币增加的数量要减少(k-n+j)个,那么dp[i+1][j+l-(k-n+j)] += dp[i][j]*san[k+1][l+1]

#include <bits/stdc++.h>

using namespace std;
const int MAXN = 110;
double dp[MAXN][MAXN];
double san[MAXN][MAXN];
int n,k,m;

int main()
{
    san[1][1] =1;
    for (int i=2;i<=100;i++)
        for (int j=1;j<=100;j++)
            san[i][j] = (san[i-1][j] + san[i-1][j-1])/2.0;
    int t;
    scanf("%d",&t);
    while (t--)
    {
        scanf("%d%d%d",&n,&m,&k);
        memset(dp,0,sizeof dp);
        dp[0][0]=1;
        for (int i=0;i<=m;i++)
        {
            for (int j=0;j<=n;j++)
            {
                for (int l=0;l<=k;l++)
                {
                    if ( n-j>=k ) dp[i+1][j+l] += dp[i][j]*san[k+1][l+1];
                    else dp[i+1][j+l-(k-n+j)] += dp[i][j]*san[k+1][l+1];
                }
            }
        }
        double ans = 0;
        for (int i=1;i<=n;i++) ans += 1.0 * i * dp[m][i];
        printf("%.3f\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/z631681297/article/details/81273504