AcWing 338. 计数问题(超短写法)


<数位Dp>


核心:

分情况讨论


简介:

自我感觉应该比提高课的还要简洁点
ps:看完一位大佬的超短题解 + 详细地加入自己想的注释 + 重新改了一点我认为的小错误后写的
该原题解贴在这啦~

虽然本蒟蒻还未看过提高课的该题思路,但看了下犇犇的好多题解都cue到了提高课,弱弱地说一句:
我觉得这个思路比提高课的应该还是要简洁些
(如果不是就当我没说啊,狗头保命)

引入原题解大佬的两句话 :

  1. 可以不用vector存每一位,直接计算某位的左边和右边的整数是多少。
  2. 可以不用讨论那么多细枝末节,只需要知道,当i为0时其左边整数不能为0,就够了。

超短写法 + 详细注释:

#include <iostream>
#include <algorithm>
#include <cmath>

using namespace std;

int get(int n) { // 求数n的位数
    int res = 0;
    while (n) res ++, n /= 10;
    return res;
}

int count(int n, int i) { // 求从1到数n中数i出现的次数
    int res = 0, dgt = get(n);
    
    for (int j = 1; j <= dgt; ++ j) {
    /* p为当前遍历位次(第j位)的数大小< 10^(右边的数的位数)>,
        l为第j位的左边的数,r为右边的数,dj为第j位上的数 */
        int p = pow(10, dgt - j), l = n / p / 10, r = n % p, dj = n / p % 10;
   
   // ps:下文的xxx、yyy均只为使读者眼熟,并不严格只是三位数啊~ 然后后续的...就代表省略的位数啦~
        /* 求要选的数在i的左边的数小于l的情况:
(即视频中的xxx1yyy中的xxx的选法) --->
    1)、当i不为0时 xxx : 0...0 ~ l - 1, 即 l * (右边的数的位数) == l * p 种选法
    2)、当1位0时 由于不能有前导零 故xxx: 0....1 ~ l - 1, 
                    		即 (l-1) * (右边的数的位数) == (l-1) * p 种选法 */
        if (i) res += l * p;
        else res += (l - 1) * p;
        
        /* 求要选的数在i的左边的数等于l的情况:(即视频中的xxx == l 时)
    (即视频中的xxx1yyy中的yyy的选法)--->
                        1)、i > dj时 0种选法
                        2)、i == dj时 yyy : 0...0 ~ r 即 r + 1 种选法
                        3)、i < dj时 yyy : 0...0 ~ 9...9 即 10^(右边的数的位数) == p 种选法 */
        if (i == dj) res += r + 1;
        if (i < dj) res += p;
    }
    
    return res;
}

int main() {
    int a, b;
    while (cin >> a >> b, a) {
        if (a > b) swap(a, b);
        for (int i = 0; i <= 9; ++ i) cout << count(b, i) - count(a - 1, i) << ' ';
        cout << endl;
    }
    
    return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值