题解 P2602 【[ZJOI2010]数字计数】
Social_Zhao · · 题解
听同机房的巨佬说,学会了数位dp就可以切掉好多好多的水紫题。
正题:
数位
初始化:
设
这里用到了前缀和的思想。比如
在求解的时候,我们就用solve(b + 1) - solve(a)。
首先我们可以得到一个粗略的方程:
#include<bits/stdc++.h>
#define int unsigned long long
#define x10(x) q_pow(10,x);
using namespace std;
const int MaxN = 15;
int f[MaxN][10][10];
int a,b;
int q_pow(int a, int b) {
int res = 1;
while(b) {
if(b & 1) res *= a;
b >>= 1;
a *= a;
}
return res;
}
void init() {
for(int i = 0; i <= 9; i++) f[1][i][i] = 1;
for(int i = 2; i <= 13; i++) {
for(int j = 0; j <= 9; j++) {
for(int k = 0; k <= 9; k++) {
for(int l = 0; l <= 9; l++) {
f[i][j][l] += f[i-1][k][l];
}
}
f[i][j][j] += x10(i-1);
}
}
}
int solve(int x, int num) {
int digit[15];
int len = 0, ans = 0;
memset(digit, 0, sizeof(digit));
while( x ) { digit[++len] = x % 10; x /= 10; }
for(int i = 1; i < len; i++) {
for(int j = 1; j <=9; j++) {
ans += f[i][j][num];
}
}
for(int i = 1; i < digit[len]; i++) {
ans += f[len][i][num];
}
for(int i = len-1; i >= 1; i--) {
for(int j = 0; j < digit[i]; j++) {
ans += f[i][j][num];
}
for(int j = len; j > i; j--) {
if(digit[j] == num) ans += digit[i] * x10(i-1);
}
}
return ans;
}
signed main() {
scanf("%lld%lld", &a, &b);
init();
for(int i = 0; i <= 9; i++) {
printf("%lld ", solve(b+1, i) - solve(a, i));
}
return 0;
}
其实这最多就一蓝题。