对于大范围 内的数字统计,需要使用数位DP的方法:
- 将问题转化为求 ,表示 到 中每个数字出现的次数则区间 的答案为
- 对于计算 :考虑每一位的贡献例如对于数字 :个位:每 个数, 各出现 次十位:每 个数,每个数字在十位上出现 次百位:每 个数,每个数字在百位上出现 次千位: 出现 次, 出现 次, 出现 次
- 核心思路:对每一位,计算该位上的每个数字出现次数需要考虑当前位是否受限
#include <iostream> #include <vector> using namespace std; typedef long long ll; // 计算每个数字在1到n中出现的次数 vector<ll> count_digits(ll n) { vector<ll> cnt(10, 0); ll pos = 1; // 位权:1, 10, 100, ... while (n >= pos) { ll high = n / (pos * 10); // 高位数字 ll curr = (n / pos) % 10; // 当前位数字 ll low = n % pos; // 低位数字 // 对0-9每个数字统计在当前位出现的次数 for (int digit = 0; digit < 10; digit++) { // 计算当前位之前的完整循环次数 cnt[digit] += high * pos; // 处理当前位 if (digit < curr) { cnt[digit] += pos; } else if (digit == curr) { cnt[digit] += low + 1; } // 处理前导零的特殊情况 if (digit == 0) { cnt[0] -= pos; // 减去前导零的情况 } } pos *= 10; } return cnt; } int main() { ll a, b; cin >> a >> b; // 计算[1,b]和[1,a-1]的统计结果 vector<ll> cnt_b = count_digits(b); vector<ll> cnt_a = count_digits(a - 1); // 输出[a,b]区间的结果 for (int i = 0; i < 10; i++) { cout << cnt_b[i] - cnt_a[i] << " "; } cout << endl; return 0; }