【题目描述】
pluto 去找妹子约会,然而要求和pluto 玩一个游戏,pluto 赢了才能获得约会的机会。游戏内容为:现在有N 个袋子(你可以认为它是哆啦A 梦的口袋,每个袋子里放着一些球),所以容量十分大,第i 个袋子里放着编号为Li 到Ri 的球(除编号外完全相同),pluto 需要从每个袋子里摸出一个球,第i 个袋子里任何一个球被摸到的概率是1/(Ri-Li + 1),如果pluto 摸出的球中有K% 或以上的球的编号的第一位是1(比如11,121,199 的第一位是1, 而21,233 第一位就不是1),那么pluto 就将赢得与约会的机会。现在pluto 想知道他能人生中第一次与妹子约会的概率有多大。【Sample Input】(第一行两个整数N,K;接下来N 行,每行两个整数,Li 和Ri)
2 50
1 2
9 11【Sample Output】(一行一个实数(保留7 位小数)表示答案绝对误差不超过10^-6)
0.8333333【数据范围】
对于100% 的数据,0 <= k<=100,0 < Li<=Ri
对于30% 的数据,n<=10,Li<=Ri<=100
对于60% 的数据,n<=500,Li<=Ri<=2000
对于100% 的数据,n<=2000,Li<=Ri<=10^18
- 【题解】
首先我们显然要先算出pluto从每个袋子里摸出第一位为1的球的概率{暴力随便做};
设从第 i 个袋子里摸出满足要求的球的概率为p[i]:
{状态} f [ i ] [ j ]:前i个袋子里取出 j 个第一位为1的球的概率
{方程} f [ i ] [ j ] = f [ i ] [ j ] = f [ i - 1 ] [ j ] * ( 1 - p [ i ] ) + f [ i - 1 ] [ j - 1 ] * p [ i ] ; //分为i-1个已取j个和取j-1个考虑
最后将取出球大于等于k%的状态累加即为答案。
#include <cstdio>
#include <iostream>
#define LL long long
LL n,k,num[2005],l[2005],r[2005];
double f[2005][2005],p[2005],ans;
int main()
{
scanf("%lld%lld\n",&n,&k);
for (int i=1;i<=n;++i) scanf("%lld%lld\n",&l[i],&r[i]);
for (int i=1;i<=n;++i)
{
LL t=1;
for (int j=0;j<=18 && t<=r[i];++j,t*=10)
if (l[i]<=t)
{
if (r[i]>=t+t-1) num[i]+=t;
else num[i]+=r[i]-t+1;
}
else if (l[i]<t+t) num[i]+=std::min(t+t,r[i]+1)-l[i];
}
for (int i=1;i<=n;++i) p[i]=1.0*num[i]/(r[i]-l[i]+1);
f[1][0]=1-p[1];f[1][1]=p[1];
for (int i=2;i<=n;++i)
for (int j=0;j<=i;++j)
f[i][j]=f[i-1][j]*(1-p[i])+f[i-1][j-1]*p[i];
int m=(n*k+99)/100;
for (int i=m;i<=n;++i) ans+=f[n][i];
printf("%.7f",ans);
return 0;
}