BZOJ1833 - 数字计数 (数位dp)

题目

给定两个正整数a和b,求在[a,b]中的所有整数中,每个数码(digit)各出现了多少次。

题解

就暴力每个数码都数位dp统计一遍。主要要注意前导0的处理,我用了一个lead参数来标明。有前导0影响的题都可以用这个参数来处理。

#include <bits/stdc++.h>

#define endl '\n'
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define FILE freopen(".//data_generator//in.txt","r",stdin),freopen("res.txt","w",stdout)
#define FI freopen(".//data_generator//in.txt","r",stdin)
#define FO freopen("res.txt","w",stdout)
#define pb push_back
#define mp make_pair
#define seteps(N) fixed << setprecision(N) 
typedef long long ll;

using namespace std;
/*-----------------------------------------------------------------*/

ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
#define INF 0x3f3f3f3f

const int N = 3e5 + 10;
const double eps = 1e-5;

ll f[100][100][20];
int di[100];

ll dfs(int p, int cnt, int d, int lmt, int lead) {
    if(!p) {
        return cnt;
    }
    if(!lmt && !lead && f[p][cnt][d] >= 0) return f[p][cnt][d];
    int maxx = lmt ? di[p] : 9;
    ll res = 0;
    for(int i = 0; i <= maxx; i++) {
        if(i == 0 && d == 0 && lead) {
            res += dfs(p - 1, cnt, d, lmt && i == maxx, i == 0 && lead);
        } else if(i == d) {
            res += dfs(p - 1, cnt + 1, d, lmt && i == maxx, i == 0 && lead);
            continue;
        } else {
            res += dfs(p - 1, cnt, d, lmt && i == maxx, i == 0 && lead);
        }
    }
    if(!lmt && !lead) f[p][cnt][d] = res;
    return res;
}

ll solve(ll x, int d) {
    int tot = 0;
    while(x) {
        di[++tot] = x % 10;
        x /= 10;
    }
    return dfs(tot, 0, d, 1, 1);
}

int main() {
    IOS;
    memset(f, -1, sizeof f);
    ll a, b;
    cin >> a >> b;
    for(int i = 0; i <= 9; i++) {
        cout << solve(b, i) - solve(a - 1, i) << " \n"[i == 9];
    }
}
posted @ 2020-08-20 21:35  limil  阅读(105)  评论(0编辑  收藏  举报