SOJ 4552 [期望,概率]

题目链接:【http://acm.scu.edu.cn/soj/problem.action?id=4552】

题意:给你n种卡牌,每种卡牌有无限多个,每次从中抽取一张卡牌,问:1、集齐这n种卡牌需要抽取次数的期望,2、抽取m次,刚好(要保证最后一抽牌刚好满足抽了n张不同的牌)集齐n张卡牌的概率。

数据范围:n<=15,m<=35;(尼玛,比赛的时候数据范围都不给清楚,只在discuss里面说了一下,还不通知)。

题解:对于第一问:公式n*(1+1/2+1/3+....+1/n);第二问:dp[i][j]:表示抽取i次,得到j张卡牌的概率。dp[i][j]->dp[i+1][j+1]+(n-j)/j;dp[i][j]->dp[i+1][j]+(j/n);

#include<bits/stdc++.h>
using namespace std;
int n, m;
double dp[55][55];
int main ()
{
    while(~scanf("%d%d", &n, &m))
    {
        if(n == 0)//当n等于0的时候,只有m也等于0的时候有意义
        {
            if(m == 0)
                printf("0.000000 1.000000\n");
            else
                printf("0.000000 0.000000\n");
            continue;
        }
        double ans1 = 0.0;
        for(int i = 1; i <= n; i++)//期望
            ans1 += double(1.0 / (double)i);
        ans1 *= (double)n;
        if(n > m)//非法状态
        {
            printf("%.6f 0.000000\n", ans1);
            continue;
        }
        if(n == 1)//当n等于1的时候,只有m也等于1的时候有意义
        {
            if(m == 1)
                printf("%.6f 1.000000\n", ans1);
            else
                printf("%.6f 0.000000\n", ans1);
            continue;
        }
        for(int i = 0; i <= 50; i++)
            for(int j = 0; j <= 50; j++)
                dp[i][j] = 0.0;
        dp[0][0] = 1.0;//dp[i][j]:表示抽取i次,得到j张卡牌的概率。
        for(int i = 0; i <= m; i++) //选的次数
            for(int j = 0; j <= n && j <= n; j++) //得到的卡牌
            {
                dp[i + 1][j + 1] += dp[i][j] * double(double(n - j) / double(n));
                dp[i + 1][j] += dp[i][j] * double(double(j) / double(n));
            }
        //要保证最后一抽牌刚好满足抽了n张不同的牌
        printf("%.6f %.6f\n", ans1, dp[m - 1][n - 1]*double(1.0 / (double)n));
    }
    return 0;
}

 

posted @ 2017-04-11 09:06  _Mickey  阅读(306)  评论(0编辑  收藏  举报