取球(概率dp)

链接:https://ac.nowcoder.com/acm/contest/1085/H
来源:牛客网

题目描述

小sun非常喜欢玩游戏,最近他和同学正在玩这样一个游戏:

小sun有一个神奇的袋子,袋子里面有C种颜色的球,每种颜色的球都有无限多个。现在小sun每次将会从袋子里拿出一个球,然后将这个球放在桌面上,如果桌面上已经有这种颜色的球了,小孙就把它们两个重新放进袋子里。

在玩的时候小sun想到了一个问题,他想问问你:在第n次拿球后,桌上有m种颜色的球的概率是多少?

输入描述:

输入一行:c,n,m代表的含义如题中所述。

输出描述:

输出一行答案,保留3位小数
示例1

输入

复制
100 100000 50

输出

复制
0.159

备注:

数据范围:
mc100
n1e12

 可一看到n很大,所以你要减小n,但是不能改变n的奇偶性(这个原理我也不知道,以后见到这样的可以减小到1e5或者1e4)

一维的写法:

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=2e5+100;
double dp[1000];
double dp1[1000]; 
ll c,n,m;
int main(){    
    cin>>c>>n>>m;
    if(n>2e5) n=2e5+n%2;
    dp[0]=1.0;
    for(int i=1;i<=n;i++){
        for(int j=0;j<=c;++j){
            if(j) dp1[j-1]+=dp[j]*((j*1.0)/(c*1.0));
            if(j!=c) dp1[j+1]+=dp[j]*((c-j)*1.0)/(c*1.0);
        }
        for(int j=0;j<=c;j++){
            dp[j]=dp1[j];
            dp1[j]=0.0;
        } 
    } 
    printf("%.3lf
",dp[m]);
} 

二维的写法;好理解

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
double dp[11000][110];
//dp[i][j]代表的是取球i次,最终桌面上有j个球的概率 
ll c,n,m;
int main(){
    cin>>c>>n>>m;
    dp[0][0]=1.0;
    if(n>=10000) n=10000+(n%2);
    for(int i=1;i<=n;i++){
        for(int j=0;j<=c;j++){
            if(j) dp[i][j]+=dp[i-1][j-1]*((c-j+1)/(c*1.0));
            if(j!=c) dp[i][j]+=dp[i-1][j+1]*((j+1)*1.0/(c*1.0)); 
        }
    }
    //可以测试一下,向后都是收敛的了 
//    for(int i=1e4-10;i<=1e4;i++){
//        printf("%.3lf
",dp[i][m]);
//    } 
    printf("%.3lf",dp[n][m]); 
} 
原文地址:https://www.cnblogs.com/lipu123/p/14295367.html