两种做法,
数位dp,这种比较好理解还有迭代模拟想好三点, (例 2048)当前数字 e 是 204 时:
当前数字个位对个位影响 , 204 % 10 = 4, 【0,4】加上 s
当前数字高位对个位影响,204 / 10 = 20, 【0, 9】加上20 * s
当前数字个位对高位影响, 【2】加上 s * (4 + 1), 【0】加上 s * (4 + 1)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int mod = 1e9 + 7; const int M = 2e2 + 10; const int N = 1e3 + 10; ll arr[N], brr[N]; //存 0~9 出现次数 // s 代表当前数字的个位是 e 的哪一位,(个位,百位,千位……) void dfs(ll s, ll e, ll c[]) // 1 到 e { ll n = e / 10; //高位 ll m = e % 10; //低位 当前位 ll t = n; for(int i = 0; i <= m; i++){ //当前数字个位对个位影响 c[i] += s; } for (int i = 0; i < 10; i++){//当前数字高位对个位影响 c[i] += s * n; } c[0] -= s; //去除前缀零 while(t){ //当前数字个位对高位影响 c[t % 10] += s * (m + 1); t /= 10; } if(n){ //n 已经处理过,从 n-1 递归 dfs(s * 10, n - 1, c); } } int main() { ll a, b; scanf("%lld%lld", &a, &b); dfs(1, a-1, arr); //计算 1 到 a-1 dfs(1, b, brr); //计算 1 到 b for(int i = 0; i < 10; i++){ printf("%lld\n", brr[i] - arr[i]); } return 0; }分开计算0~9出现几次
#include <bits/stdc++.h> #define INF 0x3f3f3f3f #define d(x) cout << (x) << endl #define lson l, m, rt<<1 #define rson m+1, r, rt<<1|1 using namespace std; typedef long long ll; const int mod = 1e9 + 7; const int N = 1e2 + 10; ll dp[N]; //18位 ll sum, len, cnt, tail, tnum; ll cal(ll num, int x) //从 1 到 a,x出现次数, x 属于0~9 { sum = len = tail = 0; cnt = 1; tnum = num; while(num){ int tmp = num % 10; //当前数字的个位 len++; if(tmp > x){ // sum += dp[len - 1] * tmp + cnt; }else if(tmp == x){ sum += dp[len - 1] * tmp + tail + 1; }else{ sum += dp[len - 1] * tmp; } tail += tmp * cnt; //当前数字后面的数 eg:2048 , 当前 20 , tail 48 cnt *= 10; //进行到第几位 num /= 10; } if(!x){ //是 0 的话删除前缀零 ll ans = 1; while(tnum){ sum -= ans; ans *= 10; tnum /= 10; } } return sum; } int main() { for(int i = 1; i <= 18; i ++) { // 0 1 20 300 4000 50000 600000 dp[i] = dp[i-1]*10 + pow(10,i-1); } ll a, b; cin >> a >> b; for (int i = 0; i < 10; i++){ cout << cal(b, i) - cal(a - 1, i) << endl; } return 0; }