BZOJ1833(数位dp)
这个数位dp倒是没什么限制条件,只是需要在过程中把每个数字出现次数记录一下即可。记忆化返回时数学算出。框架还是套板子。
1 #include <cstdio> 2 #include <cmath> 3 #include <cstring> 4 #include <iostream> 5 #include <algorithm> 6 using namespace std; 7 8 typedef long long ll; 9 ll n, m, cnt1[10], cnt2[10], dp[20][2]; 10 int tot, a[20]; 11 12 ll dfs(int pos, int state0, int limit, ll *cnt) { 13 if (!pos) { 14 cnt[0] += state0; 15 return 1; 16 } 17 if (!limit && !state0 && dp[pos][state0] != -1) { 18 for (int i = 0; i <= 9; i++) { 19 cnt[i] += pow(10, pos - 1) * pos; 20 } 21 return dp[pos][state0]; 22 } 23 24 int up = limit ? a[pos] : 9; 25 ll ret = 0; 26 27 for (int i = 0; i <= up; ++i) { 28 ll tmp = dfs(pos - 1, state0 & (!i), limit & (i == a[pos]), cnt); 29 cnt[i] += tmp; 30 if (i == 0 && state0) cnt[i] -= tmp; 31 ret += tmp; 32 } 33 34 if (!limit) dp[pos][state0] = ret; 35 return ret; 36 } 37 38 void solve(ll x, ll *cnt) { 39 for (tot = 0; x; x /= 10) 40 a[++tot] = x % 10; 41 dfs(tot, 1, 1, cnt); 42 } 43 44 int main() { 45 memset(dp, -1, sizeof dp); 46 47 cin >> n >> m; 48 solve(m, cnt1); 49 solve(n - 1, cnt2); 50 51 for (int i = 0; i <= 9; ++i) 52 printf("%lld ", cnt1[i] - cnt2[i]); 53 54 return 0; 55 }