题目
描述
中超继续进行,广州恒大和北京国安马上开赛了,比赛持续 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
1≤R≤10。
每组测试数据格式:
第一行,
A
A
A 和
B
B
B ,
0
≤
A
≤
100
,
0
≤
B
≤
100
0 \leq A \leq 100, 0 \leq B \leq 100
0≤A≤100,0≤B≤100 。
输出格式
共 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
2、3、5、7、11、13、17 这些小于等于
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=hi−1,j+hi−1,j−1
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=gi−1,j+gi−1,j−1
如果只讨论广东恒大的进球数的概率,
恒大的进球数概率为
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+Ans−Count×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 种情况,
如下表所示:(表格清晰脉络)
情况\时间片段 | 1 | 2 | 3 | 4 | 5 | 6 | … | 16 | 17 | 18 |
---|---|---|---|---|---|---|---|---|---|---|
1 | 1 | 1 | 0 | 0 | 0 | 0 | … | 0 | 0 | 0 |
2 | 1 | 0 | 1 | 0 | 0 | 0 | … | 0 | 0 | 0 |
… | … | … | … | … | … | … | … | … | … | … |
17 | 0 | 0 | 0 | 0 | 0 | 0 | … | 1 | 0 | 1 |
18 | 0 | 0 | 0 | 0 | 0 | 0 | … | 0 | 1 | 1 |
注释:( 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)18−i
可以用杨辉三角做预处理。
现在,我们回归到原题,求至少有一支球队的进球数为质数的概率,先分类讨论一下:
①. 恒大进球数为质数,国安进球数为非质数
②. 恒大进球数为非质数,国安进球数为质数
③. 恒大进球数为质数,国安进球数为质数
综上所述,把三种情况相加起来就可以得出至少有一支球队的进球数为质数的概率了。
理解了不!
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;
}
后记
如有侵权,请联系一下我,说明情况,如属实,我会立即撤回文章!