题意
给定两个(P,Q)的正整数区间((P,Q)都符合([L,R])这个区间,并且都(le 10^9)),分别从其中随机选出一个数,选出的两个数作为一个新区间的左右端点。要求新区间内的幸运数刚好为(k)个的概率(幸运数指一个数的数位只有4或7)。
分析
这题要思考着做。首先能有一个直觉:在(10^9)中间的幸运数肯定不多(2^10左右)。这个可以暴力求出。然后概率如何求?所有的情况一定是((P_r-P_l+1)(Q_r-Q_l+1))这么多,然后符合条件的幸运数区间一共有(l_tot-k+1)个(([Lucky_{i},Lucky_{i+k-1}]))这么多。为了计算所有情况,我们只能遍历所有幸运数区间,看在什么情况下能符合题意(显然不会去遍历(10^9)的P、Q的区间)。对于每个这样的([Lucky_{i},Lucky_{i+k-1}])区间,能够与他们相交的P、Q是存在两种情况的:a)P<Q;b) P>Q。我们分类讨论即可。简单地说,先计算Lucky区间与([P_l,P_r])的交集(相当于在a情况下考虑区间头),然后再计算Lucky区间与([Q_l,Q_r])的交集,将两个结果相乘即是符合第i个幸运区间的可能情况。同样地,还要对反向地(即PQ交换)再计算一遍。注意对(k=1)情况的特判。
遍历所有的幸运区间后,概率就不难求得了。
代码(Java)
/*
* ACM Code => cf110d.java
* Written by Sam X
* Date: 三月, 08, 2019
* Time: 14:27
*/
import java.util.*;
import java.math.*;
public class cf110d
{
static ArrayList<Long> vec = new ArrayList<>();
static void dfs(long x)
{
if(x>1e9) return;
if(x*10+4<1e9)
{
vec.add(x*10+4);
dfs(x*10+4);
}
if(x*10+7<1e9)
{
vec.add(x*10+7);
dfs(x*10+7);
}
}
static final long contain(long x1, long y1, long x2, long y2)
{
return Math.max(Math.min(y1,y2)-Math.max(x1,x2)+1,0l);
}
public static void main(String args[])
{
Scanner cin = new Scanner(System.in);
long pl = cin.nextLong(),
pr = cin.nextLong(),
vl = cin.nextLong(),
vr = cin.nextLong(),
k = cin.nextLong();
dfs(0);
vec.add(0l);
vec.add((long)1e9);
Collections.sort(vec);
/*
for(long x: vec)
{
System.out.print(x+" ");
}
System.out.println();
*/
long ans=0;
int sz=vec.size()-2;
for(int i=1; i<=sz-k+1; ++i)
{
int j=i+(int)k-1;
ans+=contain(vec.get(i-1)+1, vec.get(i), pl, pr)*contain(vec.get(j), vec.get(j+1)-1, vl, vr);
if(vec.get(i)>pr) break;
}
for(int i=1; i<=sz-k+1; ++i)
{
int j=i+(int)k-1;
ans+=contain(vec.get(i-1)+1, vec.get(i), vl, vr)*contain(vec.get(j), vec.get(j+1)-1, pl, pr);
if(vec.get(i)>vr) break;
}
if(k==1)
{
for(int i=1; i<=sz; ++i)
{
if(contain(vec.get(i), vec.get(i), pl, pr)!=0 &&
contain(vec.get(i), vec.get(i), vl, vr)!=0) ans--;
}
}
System.out.printf("%.12f
", (double)ans/(vr-vl+1)/(pr-pl+1));
cin.close();
}
}