幸运数4&7:给定正整数n,求不大于n的仅由4和7组成的数字的个数

时间:2021-07-21 15:11:54

 题目描述:我们称一个十进制正整数是幸运数当且仅当它只由数字4和7构成。现在给出一个正整数n,你需要计算由多少个不大于n的幸运数,由于答案可能非常大,你只需要输出答案除以1000000007后的余数。

输入:第一行包含一个整数n,1<=n<=10^100000

输出:输出对应的答案

测试样例:

125

6


21857711

254


朴素思路:逐个穷举

结果:超时,因为数目过大

思路受某位不知道姓名的大神指点,在此表示十分感谢O(∩_∩)O谢谢,思路说明:

符号说明:下面符号中,7xx表示x为4、或7,即744,777,747,774,共有2^2中可能性满足题意。

思路:由于数字仅由7、4组成,所以把满足要求的数字看做由7、4组成的“二进制”数字(7->1,4->0),这样当输入数字长度为n时,最少有幸运数4&7:给定正整数n,求不大于n的仅由4和7组成的数字的个数种情况。

例如:441,,444,777,123,731,491,594,982,长度均为3,则最少的数目为6,分别是4,7,44,47,74,77。所以,需从最高位开始向右扫描,诸位判断情况:

case1:当前位置>7,说明此位置为7或4均可满足题意(例如982,那么7xx,4xx型均满足答案;),所以答案增加2^(n-i),i为当前位置下标(例如491,i=1时,9>7,那么47x,44x均满足要求,所以答案增加2^(3-1)=4种), 并且不用再向后判断。(因为从上例子可知后续结果已被包括,因为491>4xx)

case2: 当前位置==7,说明此位置为4可满足题意(例如777,那么4xx一定满足答案;731,那么4xx一定满足答案)但对于7xx是否满足,仍需继续扫描下一位判断;如果是最后一位为7,则最后一位7或4均满足答案,答案+2(如777,i=0,4xx满足;i=1,*4x满足;i=3,因为是最后一位,所以可以判断777,774满足条件,答案+2)

case3: 7>当前位置>4,说明此位置为4可满足题意(例如594,那么4xx一定满足,且594>4xx所以后续不用在判断,已经包含).

case4: 当前位置==4,类似于==7的情况,只不过不继续向后扫描,无法准确判断(由于441等情况的存在),但是当可以扫描至最后一位且最后一位为4时(例如444),则证明44...4情况可以存在,答案+1(例如444,在xx的情况下答案再加上444这一种情况)

case5:非4非7,不满足要求,停止扫描,把之前最扫描结果返回即可(如441,只有xx满足;123,只有xx满足;)




程序说明:因为10^100000 大概等于 4^160000(可取对数大概估算一下),所以预分配160000内存



import java.util.Scanner;

public class LuckNum_4And7 {
public static void main(String[] args){
//输入n<=10^100000 约等于 4^160000 ,可以取对数算一下

int[] Bit = new int[160000];
int[] Sum = new int[160000];
Bit[0] = 1 ;//2^0 = 1
Sum[0] = 0 ;//Sum[0] = Bit[0]

for(int i = 1;i<100010;i++){//初始化,把2的幂以及求和预先算一下,方便使用
Bit[i] = Bit[i-1]*2%(1000000007);
Sum[i] =( Sum[i-1] +Bit[i])%(1000000007);
}

Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
String N = sc.nextLine();
int lenth = N.length();
int ans = Sum[lenth-1];//最短长度,例如:143,长度为三位,所以两位的长度一定满足
for(int i=0;i<lenth;i++){//从最高位开始判断,判断712,741,474,444,447,132等几种情况
if(N.charAt(i)>'7'){//当前位置大于头,以三位为例,如712,那么4xx的情况(x=4、7)均满足,那么两位xx的情况ans已求得,第三位又添加7、4两种情况
ans += Sum[lenth-i];
break;//之后全部满足,所以不用再往后按位检查
}else if(N.charAt(i)<'7'&&N.charAt(i)>'4'){//当前位==7,那么当前位为4的情况一定可以通过,当前为7的可能性还须继续向下判断,所以结果累加上4xx的情况
ans =(ans+Bit[lenth-i-1])%(1000000007);;
break;//因为是4xx,之后全部满足,所以不用再往后按位检查
}else if(N.charAt(i)=='7'){
ans =(ans+ Bit[lenth-i-1])%(1000000007);;//因为为最后一位时,加的是bit[0]=1,但最后一位为7时 应包含两种情况xx7和xx4,所以再加1
//if(i==lenth-1) ans++;
}else if(N.charAt(i)=='4'){
if(i==lenth-1) ans=(ans+1)%(1000000007);;
}else{
break;//此路不通
}
}
System.out.println(ans);

}
}
}