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];
}
}