【算法训练】数圈圈

数圈圈

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;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值