题目描述
条件概率可以通过骰子问题来阐释。在一对普通的6面骰子中,已知至少有一个骰子显示为6,那么两个骰子点数之和为12的概率是多少呢?这与下面这个问题是等价的:掷一对骰子,直到至少有一个骰子显示为6,那么最终掷出的结果两个骰子都为6的概率是多少。令人惊讶的答案是1/11,因为在36种等可能的掷骰子结果中,有11种结果至少有一个6,而这11种结果中只有1种是两个骰子都为6。
我们的目标是解决这个问题的一个广义版本。在这个版本中,我们掷 nDice 个相同的骰子,每个骰子的面标有1、2、……、maxSide。已知至少有一个骰子显示的值为 v,我们想知道骰子点数之和大于或等于 theSum 的概率。创建一个名为 Conditional 的类,其中包含一个方法 probability,该方法接收 nDice、maxSide、v 和 theSum 作为参数,并返回所需的条件概率。
输入格式
int nDice:骰子的数量
int maxSide:骰子的最大面数
int v:特定值
int theSum:目标点数和
输出格式
double:表示所求的条件概率。
数据:
in:
50
50
1
1234
out:
0.6065038966315277
这是错误代码,由输出为负数可知,开启全局 long long 后 sum 与 all,任然炸了。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=60;
double f[N][N*N][2];
int dc,msi,v,ths;
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>dc>>msi>>v>>ths;
f[0][0][0]=1;
for(int i=1;i<=dc;i++){
for(int j=0;j<=(i-1)*msi;j++){
for(int k=1;k<=msi;k++){
if(k==v) f[i][j+k][1]+=f[i-1][j][0]+f[i-1][j][1];
else {
f[i][j+k][1]+=f[i-1][j][1];
f[i][j+k][0]+=f[i-1][j][0];
}
}
}
}
int sum=0,all=0;
for(int i=0;i<=msi*dc;i++){
// cout<<f[dc][i][1]<<'\n';
if(i>=ths) sum+=f[dc][i][1];
all+=f[dc][i][1];
// cout<<sum<<' '<<all<<'\n';
}
// cout<<sum<<' '<<all<<'\n';
printf("%.20lf",(sum*1.0)/(all*1.0));
return 0;
}
但是更换为 double 后,竟然神奇的好了:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=60;
double f[N][N*N][2];
int dc,msi,v,ths;
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>dc>>msi>>v>>ths;
f[0][0][0]=1;
for(int i=1;i<=dc;i++){
for(int j=0;j<=(i-1)*msi;j++){
for(int k=1;k<=msi;k++){
if(k==v) f[i][j+k][1]+=f[i-1][j][0]+f[i-1][j][1];
else {
f[i][j+k][1]+=f[i-1][j][1];
f[i][j+k][0]+=f[i-1][j][0];
}
}
}
}
double sum=0,all=0;
for(int i=0;i<=msi*dc;i++){
// cout<<f[dc][i][1]<<'\n';
if(i>=ths) sum+=f[dc][i][1];
all+=f[dc][i][1];
// cout<<sum<<' '<<all<<'\n';
}
// cout<<sum<<' '<<all<<'\n';
printf("%.20lf",(sum*1.0)/(all*1.0));
return 0;
}
double 存大数精度这么高的吗?