1 条题解

  • 0
    @ 2025-12-14 11:28:13

    一、思路分析(超详细)

    1. 题目核心:镜像数对的定义拆解

    镜像数对要求:对于正整数对 (A,B)(A,B),需同时满足两个条件:

    • AA 的最后一位数字 = BB 的第一位数字;
    • AA 的第一位数字 = BB 的最后一位数字。

    我们的目标是统计 1A,BN1 \leq A,B \leq N 时,满足上述条件的数对总数。

    2. 暴力解法的致命问题

    若直接遍历所有 AABB(范围 1N1 \sim N),逐一验证条件:

    • 时间复杂度为 O(N2)O(N^2)
    • N=2×105N=2 \times 10^5 时,N2=4×1010N^2=4 \times 10^{10},远超计算机运算能力(1秒约能处理 10810^8 次操作),必然超时。

    因此必须通过“特征统计”优化,将时间复杂度降至 O(N)O(N)

    3. 优化核心:数字的“首位-末位”特征

    每个正整数 xx 可抽象为一个特征对 (f,l)(f, l)

    • ff(first):xx 的首位数字(正整数首位非0);
    • ll(last):xx 的末位数字(可为0)。

    镜像数对的条件可转化为: 若 AA 的特征是 (f1,l1)(f_1, l_1)BB 的特征是 (f2,l2)(f_2, l_2),则需满足: l1=f2l_1 = f_2f1=l2f_1 = l_2 → 即 BB 的特征是 (l1,f1)(l_1, f_1)

    例如:

    • A=12A=12 的特征是 (1,2)(1,2),则所有特征为 (2,1)(2,1)BB(如21、121、201等)都能和 AA 组成镜像数对;
    • 若特征为 (f,l)(f,l) 的数字有 cnt[f][l]cnt[f][l] 个,特征为 (l,f)(l,f) 的数字有 cnt[l][f]cnt[l][f] 个,则这两类数字能组成的镜像数对数量为 cnt[f][l]×cnt[l][f]cnt[f][l] \times cnt[l][f]

    4. 解题步骤(O(N) 时间复杂度)

    步骤 操作说明
    1 统计特征:遍历 1N1 \sim N 的所有数字,计算每个数字的首位 ff 和末位 ll,用二维数组 cnt[f][l]cnt[f][l] 记录该特征对的数字数量
    2 计算总数:遍历所有可能的特征对 (f,l)(f,l)f,l09f,l \in 0 \sim 9),累加 cnt[f][l]×cnt[l][f]cnt[f][l] \times cnt[l][f],得到总镜像数对数量
    3 防溢出:总数量可能极大(如 N=10000N=10000 时结果超 10610^6),需用 long long 存储结果

    5. 关键细节

    • 首位计算:通过循环除以10,直到数字小于10(如123 → 12 → 1);
    • 末位计算:直接对10取余(如123 % 10 = 3);
    • 特征对的范围:f19f \in 1 \sim 9(正整数首位非0),l09l \in 0 \sim 9,但数组可开 10×1010 \times 10 覆盖所有可能。

    二、带详细注释的C++代码

    #include <bits/stdc++.h>
    using namespace std;
    
    // 函数功能:计算正整数x的首位数字
    // 输入:正整数x
    // 输出:x的首位数字(如x=123,返回1;x=5,返回5)
    int get_swsz(int x) {
        // 循环除以10,直到x小于10(只剩最后一位,即首位)
        while (x >= 10) {  
            x /= 10;
        }
        return x;
    }
    
    int main() {
        int n;
        // 读取输入的N(所有数字的上限)
        scanf("%d", &n);
    
        // 二维计数数组:cnt[f][l] 表示“首位为f、末位为l”的数字数量
        // f和l的范围是0~9(f≠0因为正整数首位非0),数组初始化为0
        int cnt[10][10] = {0};
    
        // 遍历1~N的所有数字,统计每个数字的特征对(f,l)
        for (int x = 1; x <= n; x++) {
            // 步骤1:计算x的末位数字(对10取余)
            int last = x % 10;          
            // 步骤2:计算x的首位数字(调用自定义函数)
            int first = get_swsz(x); 
            // 步骤3:更新特征对计数:首位first、末位last的数字数量+1
            cnt[first][last]++;         
        }
    
        // 总镜像数对数量(必须用long long,避免溢出:N=2e5时总数可达(2e5)^2=4e10)
        long long total = 0;
        // 遍历所有可能的首位f(0~9)和末位l(0~9)
        for (int f = 0; f < 10; ++f) {
            for (int l = 0; l < 10; ++l) {
                // 特征对(f,l)的数字有cnt[f][l]个,特征对(l,f)的数字有cnt[l][f]个
                // 这两类数字能组成的镜像数对数量 = cnt[f][l] * cnt[l][f]
                // 累加所有组合的数量,得到总对数
                total += (long long)cnt[f][l] * cnt[l][f];
            }
        }
    
        // 输出最终结果
        cout << total << endl;
    
        return 0;
    }
    

    三、代码关键细节补充

    1. 首位计算函数 get_swsz

    • 逻辑:对于数字 xx,只要大于等于10,就不断除以10,直到只剩一位(即首位);
    • 示例:x=25x=25 → 25/10=2(<10)→ 返回2;x=1234x=1234 → 1234→123→12→1 → 返回1。

    2. 计数数组 cnt[10][10]

    • 初始化:用 {0} 初始化,确保所有元素初始值为0;
    • 索引含义:cnt[f][l] 中,第一个维度是首位 ff,第二个维度是末位 ll
    • 示例:数字11的特征是(1,1),则 cnt[1][1] +=1;数字12的特征是(1,2),则 cnt[1][2] +=1

    3. 溢出防护

    • 为什么用 long long
      假设 N=2e5N=2e5,若所有数字的特征都是(1,1),则 cnt[1][1]=2e5cnt[1][1] * cnt[1][1] = 4e10,超过 int 的最大值(约2e9),必须用 long long(最大值约9e18);
    • 强制类型转换:(long long)cnt[f][l] * cnt[l][f] 先将 cnt[f][l] 转为 long long,再相乘,避免中间结果溢出。

    4. 样例验证(以样例1 N=25为例)

    • 统计特征对:
      • (1,1):数字1、11 → cnt[1][1]=2;
      • (1,2):数字12 → cnt[1][2]=1;
      • (2,1):数字21 → cnt[2][1]=1;
      • (2,2):数字2、22 → cnt[2][2]=2;
      • (3,3)~(9,9):各1个 → cnt[3][3]~cnt[9][9]各=1;
    • 计算总数:
      • cnt[1][1]cnt[1][1] = 22=4;
      • cnt[1][2]cnt[2][1] =11=1;
      • cnt[2][1]cnt[1][2] =11=1;
      • cnt[2][2]cnt[2][2] =22=4;
      • cnt[3][3]*cnt[3][3]~cnt[9][9]cnt[9][9]:7个11=7;
      • 总和:4+1+1+4+7=17,与样例输出一致。

    四、时间/空间复杂度分析

    • 时间复杂度:O(N+10×10)=O(N)O(N + 10 \times 10) = O(N)
      遍历1~N的时间是 O(N)O(N),遍历10×10特征对的时间是常数级(100次),总复杂度由 NN 主导;
    • 空间复杂度:O(1)O(1)
      仅使用固定大小的二维数组(10×10=100个int),无额外动态空间,属于常数空间。

    该解法完全满足题目 N2×105N \leq 2 \times 10^5 的数据规模要求,运行效率极高。

    • 1

    信息

    ID
    5477
    时间
    1000ms
    内存
    256MiB
    难度
    7
    标签
    (无)
    递交数
    42
    已通过
    12
    上传者