统计数字

统计数字

问题描述
编程统计数字 k 在 0 到 n 中的出现的次数,k 可能是 0~9 的一个值。
输入
有多组数据。每组数据有一行,该有一个整数n和一个0到9之间的数字k。
输出
对每组数据,一行输出数字k在0到n中出现的次数。
输入样例
12 1
输出样例
5

最简单的算法显然是暴力枚举,
但也可以规律构造:
先考虑1~9中的数字情况,分别考虑n的每一位数字为k的数字会有多少个,计算贡献。
举个简单栗子,n = 233211, k = 2;从小到大枚举每一位,有三种情况:
1)当前位i数字小于k
十位数字上:i=2, cur = 1 < k, 高位部分数字 h = 2332,低位数字 l = 1。那么十位数字为2的情况: 20 ~ 29, 120 ~ 929, …, 1020 ~ 9929,233120~233129,。
也就是是固定个位为2,高位数字从0 ~ 2331中取值,低位数字从0 ~ 9中取值,个位为2对答案的贡献就是:2332 * 10;
贡献可概括为: h * 10 ^ (i - 1)
2)当前位i数字等于k
枚举到百位,i = 3,cur = 2 = k,h = 233,低位数字 l = 11,那么百位为1的数字可能取值为:200 ~ 299,1200 ~ 9299,…, 232200 ~ 23299,这部分和前面cur < k的情况类似,但还有一部分233200 ~ 233311, 共11个,多出部分的数字等于低位数字(l = 11)+1
贡献可概括为: h * 10 ^ (i -1) + l + 1;
3)当前位i数字大于k
枚举到千位,i = 4,cur = 3 > k,h = 23,低位数字 l = 211,那么千位为1的数字可能取值为:2000 ~ 2999,12000 ~ 92990,…, 232200 ~ 2322999;也就是是固定千位为2,高位数字从0 ~ 22中取值,低位数字从0 ~ 999中取值,千位为2对答案的贡献就是:23 * 1000;
贡献可概括为: (h + 1) * 10 ^ (i -1) ;

再考虑k = 0的特殊情况:
k = 0 特殊地方在于其最高位数字不能为0,
同上 n = 233211, k = 0;
枚举十位,固定十位数字为0,此时h = 2332,l = 1,由于最高位不能为0,所以高位取值变为1 ~ 2331,低位数字取值0~9,也就是说高位部分贡献h比k > 0部分少1。

code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll solve(ll n, int k){
    if(k == 0 && n == 0) return 1; // 0 0
    ll l, h, cur, pos = 1, ans = 0;
    while(n / pos > 0){
        if(k == 0 && n / (pos * 10) == 0){ //当前位为0,最高位数字不能为0
            ++ans; //注意ans++,这里算的是特殊数字0
            break ;
        }
        cur = (n / pos) % 10;
        l = n - (n / pos) * pos;
        h = n / (pos * 10);
        if(k == 0) --h;//k = 0,高位数字贡献减一
        if(cur < k){
            ans += h * pos;
        }
        else if(cur == k){
            ans += h * pos + l + 1LL;
        }
        else{
            ans += (h + 1) * pos;
        }
        pos *= 10;
    }
    return ans;
}

ll bfsolve(ll n,int k){
    ll ans = (0 == k);
    for(ll i = 1; i <=n; ++i){
        ll tmp = i;
        while(tmp){
            if(tmp % 10 == k) ++ans;
            tmp /= 10;
        }
    }
    return ans;
}

int main(){
    int k;
    ll n;
    while(cin >> n >> k){
        cout << solve(n, k) << endl;
        cout << bfsolve(n,k) << endl;
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值