题意:
出个两个(P,V)范围在1e9的正整数区间,分别从其中随机选出一个数,选出的两个数作为一个新区间的左右端点。要求新区间内的幸运数刚好为k个的概率(幸运数指一个数的数位只有4或7)。
思路:
首先可以dfs找出所有在数据范围内的幸运数,记为L数组,因为数目不多,便可成k段遍历 L数组,每次分别计算【 L[i-1]+1,L[i]】与【Pl,Pr】的线段交集,和【 L[i+k-1],L[i+k]-1】与【Vl,Vr】的线段交集,将两个结果相乘即是符合[i,i+k-1]区间幸运数的可能情况,同样的还要对P,V两个区间交换后在计算一遍,概率=所有可能情况/(Pr-Pl+1)/(Vr-Vl+1);
然后还要注意k==1的情况会重复计算,需特判。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll L[1050];
int num=0;
void dfs(int len,int p,int v)
{
if(p==len)
{
L[++num]=v;
return;
}
dfs(len,p+1,v*10+4);
dfs(len,p+1,v*10+7);
}
ll contain(ll x1,ll y1,ll x2,ll y2)
{
ll l=max(x1,x2);
ll r=min(y1,y2);
return r-l+1>0?r-l+1:0;
}
int main()
{
for(int len=1;len<=9;len++) dfs(len,0,0);
L[0]=0;
L[++num]=1000000000;
//for(int i=1;i<=num;i++) printf("%d %lld\n",i,L[i]);
ll Pl,Pr,Vl,Vr;
int k;
scanf("%lld%lld%lld%lld%d",&Pl,&Pr,&Vl,&Vr,&k);
ll sum=0;
for(int i=1;i<=1022-k+1;i++)
{
int j=i+k-1;
sum+=contain(L[i-1]+1,L[i],Pl,Pr)*contain(L[j],L[j+1]-1,Vl,Vr);
if(L[i]>Pr) break;
}
for(int i=1;i<=1022-k+1;i++)
{
int j=i+k-1;
sum+=contain(L[i-1]+1,L[i],Vl,Vr)*contain(L[j],L[j+1]-1,Pl,Pr);
if(L[i]>Vr) break;
}
if(k==1)
{
for(int i=1;i<=1022;i++)
{
if(contain(L[i],L[i],Pl,Pr)&&contain(L[i],L[i],Vl,Vr)) sum--;
}
}
printf("%.10f\n",sum*1.0/(Vr-Vl+1)/(Pr-Pl+1));
}