题意:

有n个反面朝上的硬币,每次可以选a个硬币扔,要扔m次,目的是尽可能得让正面朝上的硬币多。问硬币正面朝上的期望为多少。

思路:

题目又看错了…主要是样例手算不出来…就以为本来的理解是对的…

事实上它是有贪心在里面的,因为尽可能要让正面朝上的硬币多,所以每次尽可能扔反面朝上的硬币,如果反面朝上的硬币不足a个的话,把反面朝上的硬币全选了以外正面朝上的硬币也选几个。

这里就可以dp了。

对于某个状态,再扔一次a个硬币中有l个硬币正面朝上的概率为

当反面朝上的硬币大于等于a个的话,有转移,其中,表示这次扔正面朝上的硬币数。

当反面朝上的硬币小于a个的话,有转移,其中

边界条件为

再算一下期望就可以了。

代码:

double dp[110][110];//扔i次有j面朝上的概率
double c[110][110],xs[110];
void init()
{
    c[0][0]=1;
    for(int i=1;i<=100;i++)//j是上面,i是下面
    {
        c[i][0]=1;
        for(int j=1;j<=i;j++)
        {
            c[i][j]=c[i-1][j]+c[i-1][j-1];
        }
    }
    xs[1]=0.5;
    for(int i=2;i<=100;i++)
        xs[i]=0.5*xs[i-1];
}
int main()
{
    int t,n,m,a;
    init();
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d",&n,&m,&a);//n个硬币扔m次每次扔a个
        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 k=0;k<=a;k++)//有k枚硬币向上
                {
                    if(n-j>=a)dp[i+1][j+k]+=dp[i][j]*c[a][k]*xs[a];
                    else dp[i+1][j-(a-n+j)+k]+=dp[i][j]*c[a][k]*xs[a];
                }
            }
        }
        /*for(int i=1;i<=m;i++)
        {
            for(int j=0;j<=n;j++)
                printf("%.3f ",dp[i][j]);
            printf("\n");
        }*/
        double ans=0;
        for(int i=0;i<=n;i++)
            ans+=dp[m][i]*i;
        printf("%.3f\n",ans);
    }
    return 0;
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

HDU6219 思维+单调队列 Previous
徐州邀请赛G 分块思想+前缀积后缀积 Next