2021年蓝桥杯C/C++B组F题-123

假定读者已经看过其他题解,这里提供一个较为清晰的Java代码思路。

import java.io.*;
import java.util.*;

public class Main {

    // 对于本题来说,1e12内的数用本题的表示法,
    // 分别按12,123,1234,12345...划分成1,2,3...行,可在1500000行   内划分完毕
    static int N = 1500000;
    static long a[] = new long[N], s[] = new long[N], row[] = new long[N];
    static long left, right;

    public static long work(){
        // 在a[]中找到最小的大于等于left的值,同时也会找到left所在的二维行数
        int l = 1, r = N - 1;
        while(l < r){
            int mid = l + r >> 1;
            if(a[mid] >= left) r = mid;
            else l = mid + 1;
        }
        long tl = a[r]; // 记录第tlidx行最后一位数的一维下标
        int tlidx = r; // 记录left所在的行数
        int ctlidx = tlidx - (int)(tl - left); // 记录left所在的列数
        // 在a[]中找到最小的大于等于right的值,同时也会找到right所在的二维行数
        l = 1; r = N - 1;
        while(l < r){
            int mid = l + r >> 1;
            if(a[mid] >= right) r = mid;
            else l = mid + 1;
        }
        long tr = a[r]; // 记录第tridx行最后一位数的一维下标
        int tridx = r; // 记录right所在的行数
        int ctridx = tridx - (int)(tr - right); // 记录right所在的列数

        // 如果left和right在同一行,按前缀和a[]返回
        long res = 0;
        if(tridx - tlidx == 0) res = a[ctridx] - a[ctlidx - 1];
        else {
            // 如果二者不在同一行
            res += s[tridx - 1] - s[tlidx]; // 先加它俩间所有行的和
            res += a[tlidx] - a[ctlidx - 1]; // 再加left所在行从它到行尾所有数的和
            res += a[ctridx]; // 再加right所在行从头到它所有数的和
        }
        return res;
    }

    public static void init(){
        // a[i]即表示第i行的和,又表示第i行最后一个数对应一维的下标
        for(int i = 1; i < N; i++) a[i] = a[i - 1] + i;
        // s[i]表示前i行所有数的和
        for(int i = 1; i < N; i++) s[i] = s[i - 1] + a[i];
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        StreamTokenizer stmInput = new StreamTokenizer(br);
        stmInput.nextToken();
        int T = (int)stmInput.nval;
        // 1.预处理a[], s[]
        init();
        while(T-- != 0){
            stmInput.nextToken();
            left = (long)stmInput.nval;
            stmInput.nextToken();
            right = (long)stmInput.nval;
            bw.write(work() + "\n");
        }
        bw.flush();
        bw.close();
        br.close();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值