【概率/数学】进球数 详细题解


题目

描述

中超继续进行,广州恒大和北京国安马上开赛了,比赛持续 90 90 90 分钟,为了分析方便,我们把 5 5 5 分钟作为一个时间片,那么比赛会进行 18 18 18 个时间片。在每一个时间片内,恒大踢进 1 1 1 球的概率百分比都是 A % A\% A%,国安踢进1球的概率都是 B % B\% B%。当比赛结束后,两支球队当中,至少有一支球队的进球数是质数的概率是多少?

在这里插入图片描述


输入格式

第一行,一个整数 R R R ,表示有 R R R 组测试数据。 1 ≤ R ≤ 10 1 \leq R \leq 10 1R10
每组测试数据格式:
第一行, A A A B B B 0 ≤ A ≤ 100 , 0 ≤ B ≤ 100 0 \leq A \leq 100, 0 \leq B \leq 100 0A100,0B100

输出格式

R R R 行,每行一个实数,表示概率。

输入/输出例子

输入

3
50 50
100 100
12 89

输出

0.5265618908306351
0.0
0.6772047168840167

提示

本题只需算得出结果即可,无需在意保留小数点后几位的问题。


题意

在这场中超比赛中,把比赛分为 18 18 18时间片
广州恒大和北京国安在每个时间片中踢进 1 1 1 球的概率百分比分别为 A % A\% A% B % B\% B%
求在 18 18 18 个时间片内至少有一支球队的进球数质数的概率。

解题思路

本题要求出在 18 18 18 个时间片内至少有一支球队的进球数质数的概率。
因为两支队伍分别在每个时间片内都最多只能踢进 1 1 1 球,这场比赛只有 18 18 18时间片,故两支队伍分别最多只能踢进 18 18 18 球。
如果一支球队的进球数为质数,那么这支队的进球数只能是 2 、 3 、 5 、 7 、 11 、 13 、 17 2、3、5、7、11、13、17 2357111317 这些小于等于 18 18 18质数

根据题意,我们可以使用两个动态dp解决这个问题。
h i , j h_{i,j} hi,j 表示广东恒大在前 i 个时间片中踢进 j 个球的概率数
g i , j g_{i,j} gi,j 表示北京国安在前 i 个时间片中踢进 j 个球的概率数
状态转移方程
h i , j = h i − 1 , j + h i − 1 , j − 1 h_{i,j}=h_{i-1,j}+h_{i-1,j-1} hi,j=hi1,j+hi1,j1
g i , j = g i − 1 , j + g i − 1 , j − 1 g_{i,j}=g_{i-1,j}+g_{i-1,j-1} gi,j=gi1,j+gi1,j1

如果讨论广东恒大的进球数的概率
恒大的进球数概率为 18 18 18 个时间片中踢进的球的个数为质数的总和,即 C o u n t = ∑ i = 2 17 h 18 , i Count=\sum_{i=2}^{17}h_{18,i} Count=i=217h18,i
若也单独讨论北京国安(用Ans表示)的进球数的概率,与恒大的计算方法同理
再把恒大和国安的概率相加便可;

这样的思路看上去好像没什么问题了,但你就以为这么做完事了?
错!这是只完成了整个程序的 90 % 90\% 90%
仔细一查,便可发现我们在计算时只讨论了恰好 有一支球队的进球数为质数的概率,却忽略了题目中的“至少”二字,说明我们还要讨论两支球队的进球数都是质数的情况,所以我们刚刚所算得概率中有算重复的,因此需把重复的部分去掉,用乘法原理,即用广东恒大和北京国安的进球概率的和减去恒大和国安进球概率的乘积
S u m = C o u n t + A n s − C o u n t × A n s Sum=Count+Ans-Count \times Ans Sum=Count+AnsCount×Ans。 式 A A A
( C o u n t Count Count 表示的是恒大 A n s Ans Ans 表示的是国安 )

最后直接把公式中的 C o u n t Count Count A n s Ans Ans 代入 A A A 中计算即可。

如果还没看懂的,可以继续帮你把题目划分为子问题解决,加深理解。
此处参考大佬的部分题解思路(有略删改)
根据题意,简化一下问题,我们先单独考虑一支球队进球数是质数的概率。(子问题)
继续简化问题,如果这支球队进球数 2 2 2(子问题),那么球队在 18 18 18 个时间片段内进 2 2 2 球的情况可以用 0 0 0 1 1 1 ,即选和不选来表示,用组合数学来计算,故有 C 18 2 C_{18}^{2} C182 种情况,
如下表所示:(表格清晰脉络

情况\时间片段123456161718
1110000000
2101000000
17000000101
18000000011

注释:( 1 1 1 表示 0 0 0 表示不选)

在这 18 18 18 个时间片段中,只有 2 2 2 个时间片段进球,其他时间片段不能进球的情况下才符合当前题意,而这种情况又有 C 18 2 C_{18}^{2} C182 ​种,所以设进球概率 P ( g o a l ) P(goal) P(goal),球队在 18 18 18 个时间片段内进 2 2 2 球这种情况的概率是:
C 18 2 × P ( g o a l ) 2 × P ( g o a l ) 16 C_{18}^{2} \times P(goal)^2 \times P(goal)^{16} C182×P(goal)2×P(goal)16
那么是在 18 18 18 个时间片里进 i 个球的情况的概率:
C 18 i × P ( g o a l ) i × P ( g o a l ) 18 − i C_{18}^{i} \times P(goal)^i \times P(goal)^{18-i} C18i×P(goal)i×P(goal)18i

可以用杨辉三角预处理

现在,我们回归到原题,求至少有一支球队的进球数为质数的概率,先分类讨论一下:

①. 恒大进球数为质数,国安进球数为非质数
②. 恒大进球数为非质数,国安进球数为质数
③. 恒大进球数为质数,国安进球数为质数

综上所述,把三种情况相加起来就可以得出至少有一支球队的进球数为质数的概率了。
理解了不!

Code(质数)

#include<bits/stdc++.h>
using namespace std;
int r,a,b,z[15]={0,2,3,5,7,11,13,17};
double f[25][25],g[25][25];
int main(){
	scanf("%d",&r);
	while(r--){
		scanf("%d%d",&a,&b);
		f[0][0]=g[0][0]=1;
		double Count=0,Ans=0,Sum=0;
		for(int i=1;i<=18;i++){
			for(int j=0;j<=i;j++){
				f[i][j]=f[i-1][j]*(100-a)*1.0/100;
				g[i][j]=g[i-1][j]*(100-b)*1.0/100;
				if(j==0) continue;
				f[i][j]+=f[i-1][j-1]*a*1.0/100;
				g[i][j]+=g[i-1][j-1]*b*1.0/100;
			}
		}
		for(int i=1;i<=7;i++)
			Count+=f[18][z[i]],Ans+=g[18][z[i]];
		cout<<Count+Ans-Count*Ans<<"\n";
	}
	return 0;
}

但是,除此之外还有一种更简单的方法。
至少有一支球队的进球数为质数的概率 = 1 − =1 - =1 两支球队进球数都是非质数(即合数)的概率即可,(正难反则易)。

Code2(合数)

#include<bits/stdc++.h>
using namespace std;
int r,a,b,c[25][25],z[15]={0,1,4,6,8,9,10,12,14,15,16,18};
double f[25],g[25],Ans=0;
void init(){
	for(int i=0;i<=18;i++){
		c[i][0]=1;
		c[i][i]=1;
	}
	for(int i=1;i<=18;i++)
		for(int j=1;j<i;j++)
			c[i][j]=c[i-1][j]+c[i-1][j-1];
}
signed main(){
	scanf("%d",&r);
	init();
	while(r--){
		scanf("%d%d",&a,&b);
		Ans=0;
		for(int i=0;i<=18;i++){
			double tmpf1,tmpf2;
			double tmpg1,tmpg2;
			tmpf1=tmpf2=tmpg1=tmpg2=1;
			for(int j=1;j<=i;j++)
				tmpf1*=a*0.01,tmpg1*=b*0.01;
			for(int j=1;j<=18-i;j++)
				tmpf2*=1.00-a*0.01,tmpg2*=1.00-b*0.01;
			f[i]=c[18][i]*tmpf1*tmpf2;
			g[i]=c[18][i]*tmpg1*tmpg2;
		}
		for(int i=0;i<=11;i++)
			for(int j=0;j<=11;j++)
				Ans+=f[z[i]]*g[z[j]];
		Ans=1.00-Ans;
		cout<<Ans<<"\n";
	}
    return 0;
}

后记

如有侵权,请联系一下我,说明情况,如属实,我会立即撤回文章!

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值