tabris有一个习惯,无聊的时候就会数圈圈,无论数字还是字母。
现在tabris更无聊啦,晚上睡不着觉就开始数羊,从a只数到b只。
顺便还数了a到b之间有多少个圈。
但是tabris笨啊,虽然数羊不会数错,但很可能数错圈的个数。
但是tabris很难接受自己笨这个事实,所以想问问你他一共应该数出多少个圈,这样tabris才好判断他到底笨不笨啊。
输入描述:
输入一个T,表示数据组数
每组测试数据包含两个正整数a,b。
T∈[1,50]
a,b∈[1,106]
输出描述:
每组数据输出结果,并换行。
示例1
输入
11
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
10 10
1 100
输出
0
0
0
1
0
1
0
2
1
1
111
初始化圈数数组:根据题目要求,数字0、4、6、8、9分别对应的圈数被正确设置。
输入处理:读取输入的测试用例数T,然后逐个处理每个a和b的范围。
计算圈数总和:通过计算每个关键数字(0、4、6、8、9)在a到b范围内的出现次数,并乘以对应的圈数,累加得到总和。
countDigit函数:高效计算0到x中某个数字d的出现次数,使用数位统计的方法确保时间复杂度为O(log x),极大优化了性能。
该方法利用数位动态统计技术,高效处理大范围数据,确保在时间和空间复杂度上均能胜任题目要求。
import java.util.Scanner;
public class Main {
static int[] circle = new int[10];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int T = sc.nextInt();
// 初始化圈数数组:0、4、6、8、9有圈
circle[0] = 1;
circle[4] = 1;
circle[6] = 1;
circle[8] = 2;
circle[9] = 1;
for (int t = 0; t < T; t++) {
int a = sc.nextInt();
int b = sc.nextInt();
long sum = 0;
// 计算各数字的出现次数贡献
sum += (countDigit(b, 0) - countDigit(a-1, 0)) * circle[0];
sum += (countDigit(b, 4) - countDigit(a-1, 4)) * circle[4];
sum += (countDigit(b, 6) - countDigit(a-1, 6)) * circle[6];
sum += (countDigit(b, 8) - countDigit(a-1, 8)) * circle[8];
sum += (countDigit(b, 9) - countDigit(a-1, 9)) * circle[9];
System.out.println(sum);
}
sc.close();
}
// 计算0到x中数字d的出现次数
public static long countDigit(int x, int d) {
if (x < 0) return 0;
long count = 0;
long base = 1;
while (base <= x) {
long divider = base * 10;
long higher = x / divider;
long current = (x / base) % 10;
long lower = x % base;
if (d == 0) {
if (higher > 0) {
if (current > 0) {
count += higher * base;
} else {
count += (higher - 1) * base + lower + 1;
}
}
} else {
if (current > d) {
count += (higher + 1) * base;
} else if (current == d) {
count += higher * base + lower + 1;
} else {
count += higher * base;
}
}
base *= 10;
}
// 处理数字0的特殊情况
if (d == 0) count++;
return count;
}
}