[ZJOI2010]数字计数 题解

wr硬着头皮写了一发竟然过了?

谈一谈我的做法。

思路:数位dp+分类讨论。

考虑分成一个一个位考虑。加上前缀和思想,本题就转化成了“$1-x$中$y$出现的个数”。

再分个类,考虑限定数位在每一个数中必须出现的个数,那么本题就又转化成了“$1-x$中$y$出现$z$次的数的个数”。

这玩意是个简单到不能再简单的数位dp模型了。可以直接套模型求解。

那么本题就完美解决了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
/**
* @Author: Mingyu Li
* @Date: 2019-03-11T12:13:29+08:00
* @Email: class11limingyu@126.com
* @Filename: [ZJOI2010]数字计数.cpp
* @Last modified by: Mingyu Li
* @Last modified time: 2019-03-13T19:36:56+08:00
*/

#include <bits/stdc++.h>
#define tpname typename
#define int long long
#define Go(i , x , y) for(register int i = x; i <= y; i++)
#define God(i , y , x) for(register int i = y; i >= x; i--)
typedef long long LL;
typedef long double ld;
typedef unsigned long long ULL;
template < tpname T > void sc(T& t) {
char c = getchar(); T x = 1; t = 0; while(!isdigit(c)) {if(c == '-') x = -1; c = getchar();}
while(isdigit(c)) t = t * 10 + c - '0' , c = getchar();t *= x;
}
template < tpname T , tpname... Args > void sc(T& t , Args&... args) {sc(t); sc(args...);}
template < tpname T > T mul(T x , T y , T _) {
x %= _,y %= _; return ((x * y - (T)(((ld)x * y + 0.5) / _) * _) % _ + _) % _;
}

const int N = 20;
LL dp[N][N] , d[N];
// 啥意思?
// dp[i][j] : 填了i位 共填了j个有效数字 接下来"能动"的数个数
int l , r , sup;
LL f(LL x, LL y) {
if(dp[x][y] != -1) return dp[x][y];
if(x == 0) return dp[x][y] = y == sup ? 1 : 0;
else return dp[x][y] = 9 * f(x-1 , y) + f(x-1 , y+1);
}

LL cal(LL D , LL digit) {
memset(dp , -1 , sizeof(dp));
int m=0;
while(D) {
d[m++] = D%10; D /= 10;
}
int ans = 0;
Go(occur , 0 , 13) {
sup = occur;
memset(dp , -1 , sizeof(dp));
Go(i , 1 , m-1) {
Go(j , 1 , 9) {
ans += occur * f(i-1 , (j == digit));
}
}
}
Go(occur , 0 , 13) {
sup = occur;
memset(dp , -1 , sizeof(dp));
int pref = 0;
God(i , m-1 , 0) {
Go(j , (i == m-1) ? 1 : 0 , d[i] - 1) {
ans += occur * f(i , pref + (j == digit));
}
pref += (d[i] == digit);
if(pref > occur) break;
}
}
return ans;
}
signed main() {
std::cin >> l >> r;
for(int i = 0; i <= 9; i++) std::cout << cal(r+1 , i) - cal(l , i) << " ";
return 0;
}

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×