Atcoder dp I Coins 题解

Atcoder链接:Coins

Luogu链接:Coins


$\scr{\color{BlueViolet}{Solution}}$

观察数据,发现$ \cal{n} \le 3000 $,说明 $ Ο(\cal{n^2}) $可过,容易想到DP。

用 $\cal{dp[i][j]}$ 表示抛完第$\cal{i}$个硬币时,有$\cal{j}$个硬币正面朝上的概率。

 考虑$\cal{dp[i][j]}$如何转移,易发现有以下两种情况,(当前正面朝上概率为 $\cal{p_i}$):

  • 本次抛得硬币是正面:抛到正面概率 乘 抛完第$\cal{i-1}$个硬币后,有$j-1$个硬币朝上的概率。
  • 本次抛得硬币是反面:抛到反面概率 乘 抛完第$\cal{i-1}$个硬币后,有$j$个硬币朝上的概率。

我们把以上两种情况表示出来,也就是:${dp[i][j]} = {p_i}  \times {dp[i-1][j-1]} + {1-p_i} \times {dp[i-1][j]}$

初始值:$\cal{dp[0][0]=1}$,因为第$0$次抽到$0$张卡的概率一定是$1$。

其余$dp[i][j]$值都为0。

然后就好了,最后统计一下符合条件的所有可能情况。

时间复杂度:$\cal{O(n^2)}$

Code:

//From:201929
#include<bits/stdc++.h>
#define L long long
using namespace std;
double a[3005];
double dp[3005][3005];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%lf",&a[i]);
    dp[0][0]=1;
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<=i;j++)
        {
            if(i==j) dp[i][j]+=dp[i-1][j-1]*a[i];
            else if(j!=0) dp[i][j]+=dp[i-1][j-1]*a[i]+dp[i-1][j]*(1-a[i]);
            else dp[i][j]+=dp[i-1][j]*(1-a[i]);
        }
    }
    double summ=0;
    for(int i=1;i<=n;i++)
    if(i>n-i) summ+=dp[n][i];
    printf("%.9lf",summ);
    return 0;
}

 

posted @ 2023-01-10 22:58  201929  阅读(58)  评论(0编辑  收藏  举报