题意: 给出 [L,R]区间,区间里的每个数出现的概率是1/(R-L+1), 现给出n个区间[Li,Ri ] 现在从每个区间选取一个数,这n个数种至少K%个数前缀为1的概率
这个题目主要是求出区间[ L,R] 里前缀为1的概率,然后概率dp即可
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int inf=0x3fffffff;
const int maxn=1010;
double dp[maxn][maxn];
typedef long long ll;
int digit[20];
ll fac[20];
ll cal(ll n)
{
int pos=0;
for(;n;pos++,n/=10) digit[pos]=n%10;
ll ret=0;
bool ok=0;
for(int i=pos-1;i>=0;i--)
{
if(digit[i]>=2||ok) ret+=fac[i];
else if(digit[i]==1){
ll tmp=1;
for(int j=0;j<i;j++) tmp+=digit[j]*fac[j];
ret+=tmp;
}
if(digit[i]>=1) ok=1;
}
return ret;
}
ll check(ll n)
{
ll ret=0;
for(ll i=1;i<=n;i++)
{
ll tmp=i,last;
for(;tmp;tmp/=10) last=tmp%10;
if(last==1) ret++;
}
return ret;
}
int main()
{
fac[0]=1;
for(int i=1;i<20;i++) fac[i]=10*fac[i-1];
int n,K;
ll L,R;
while(scanf("%d",&n)==1)
{
memset(dp,0,sizeof(dp));
dp[0][0]=1;
for(int i=1;i<=n;i++)
{
scanf("%I64d %I64d",&L,&R);
ll num=cal(R)-cal(L-1);
double p=num*1.0/(R-L+1.0);
for(int j=i-1;j>=0;j--)
{
dp[i][j+1]+=dp[i-1][j]*p;
dp[i][j]=dp[i-1][j]*(1-p);
}
}
scanf("%d",&K);
int x=n;
while(x>=0&&x*100>=n*K) x--;
x++;
double ans=0;
for(int i=x;i<=n;i++) ans+=dp[n][i];
printf("%.15lf\n",ans);
}
return 0;
}