题目描述
时间限制:1秒
空间限制:32768K
给定两个整数 l 和 r ,对于所有满足1 ≤ l ≤ x ≤ r ≤ 10^9 的 x ,把 x 的所有约数全部写下来。对于每个写下来的数,只保留最高位的那个数码。求1~9每个数码出现的次数。
输入描述: 一行,两个整数 l 和 r (1 ≤ l ≤ r ≤ 10^9)。
输出描述: 输出9行。第 i 行,输出数码 i 出现的次数。
输入例子: 1 4
输出例子:
4 2 1 1 0 0 0 0 0
暴力法O(n)
改进的算法O(sqrt n)
import java.util.Scanner;
public class CodemDigits {
public static void solve(int l, int r) {
/* brute force
long[] c1 = bruteForce(l-1, l-1);
long[] c2 = bruteForce(r, r);
for(int i=1; i<10; i++) {
System.out.println(c2[i]-c1[i]);
}
*/
long[] cl = countFactor(l-1);
long[] cr = countFactor(r);
for(int i=1; i<10; i++) {
System.out.println(cr[i]-cl[i]);
}
}
static int[] unit = {1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000};
public static long[] bruteForce(int upper, int maxFactor) {
long[] c = new long[10];
int unitIndex = 0;
for(int factor=1; factor<=maxFactor; factor++) {
int count = upper/factor;
int highest = factor/unit[unitIndex];
if(highest > 9) {
unitIndex++;
highest /= 10;
}
c[highest] += count;
}
return c;
}
public static long[] countHighest(int from, int to) {
long[] c = new long[10];
if(from > to) {
return c;
}
if(to == 1000000000) {
c[1]++;
to -= 1;
}
for(int i=0; i
to) break;
if(from <= unit[i] && unit[i+1]-1 <= to) {
for(int h=1; h<10; h++) {
c[h] += unit[i];
}
continue;
}
for(int h=Math.max(from/unit[i], 1); h<10 && h<=to/unit[i]; h++) {
c[h] += unit[i];
if(h*unit[i] < from) {
c[h] -= from - h*unit[i];
}
if((h+1)*unit[i]-1 > to) {
c[h] -= (h+1)*unit[i] - 1 - to;
}
}
}
return c;
}
public static long[] countFactor(int upper) {
if(upper <= 1000000) {
return bruteForce(upper, upper);
}
long[] c = new long[10];
/** count factor that appear < 1000 times **/
//maxFactor[i] is the max factor that appears at least i times
int[] maxFactor = new int[1001];
for(int t=1; t<=1000; t++) {
maxFactor[t] = upper/t;
}
for(int t=1; t<=999; t++) {
long[] tmp = countHighest(maxFactor[t+1]+1, maxFactor[t]);
for(int i=1; i<10; i++) {
c[i] += tmp[i] * t;
}
}
/** count factor that appear >= 1000 times **/
long[] tmp = bruteForce(upper, maxFactor[1000]);
for(int i=1; i<10; i++) {
c[i] += tmp[i];
}
return c;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int l = sc.nextInt();
int r = sc.nextInt();
sc.close();
solve(l,r);
}
}

本文介绍了一道CodeM美团点评编程大赛中的题目,任务是在给定范围内统计每个数字1到9作为约数最高位出现的频次。文章提供了一个高效的算法实现,采用O(sqrtN)的时间复杂度来解决问题。
335

被折叠的 条评论
为什么被折叠?



