[nowcoder 17385]Beautiful Number 题解

一句话:卡常无所不能。

套路比较sb…强制总和是多少,于是就转化成了总和为此数且这个数能被总和整除的数的个数。
搞个三维dp爆算了一波,答案是对的,但是一组数据跑了0.4s.

看了一眼——100组数据,岂不是凉凉?
开始卡常数。
先把不用开long long的都换掉,再改register int,再改取模运算,然而这些都没有特别明显的效果。

灵机一动了一下:可以在记忆化搜索里面剪枝!
大概就是总和不可能等于假定值的要被剪掉。然后速度飞快,快到了0.11s左右。
估算了一波,跑完100组需要11s.于是又加了一个当前dp数组的memset优化,快到了0.083s左右。
换成scanf, printf, 卡了一下就过了。

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
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int d[20], m = 0;

ll ans, l, r;
int now;
ll dp[14][109][109];
int xxx[169400], yyy[169400], zzz[169400], cnt;
ll DP(int i, int mod, int sum) {
if(dp[i][mod][sum] != -1) return dp[i][mod][sum];
if(sum>now) return xxx[++cnt] = i, yyy[cnt] = mod, zzz[cnt] = sum, dp[i][mod][sum]=0;
if(sum+(9*i)<now) return xxx[++cnt] = i, yyy[cnt] = mod, zzz[cnt] = sum, dp[i][mod][sum]=0;
if(!i) {
xxx[++cnt] = i, yyy[cnt] = mod, zzz[cnt] = sum;
if(sum == now && mod == 0) return dp[i][mod][sum] = 1;
else return dp[i][mod][sum] = 0;
}

dp[i][mod][sum] = 0;
for(register int dg = 0; dg <= 9; dg++) dp[i][mod][sum] += DP(i-1,(mod * 10 + dg) % now, sum + dg);
xxx[++cnt] = i, yyy[cnt] = mod, zzz[cnt] = sum;
return dp[i][mod][sum];
}

ll calc(ll x) {
m = 0;
while(x) {
d[m++] = x%10; x /= 10;
}
memset(dp, -1, sizeof(dp));
// m - 1 :
ll ret = 0;
for(register int xx = 1; xx <= 9*m; xx++) {
now = xx;
cnt = 0;
ll ans = 0;
for(register int i = m-1; i >= 1; i--)
for(register int j = 1; j <= 9; j++)
ans += DP(i-1, j-j/now*now, j);
int pre1 = 0, pre2 = 0;
for(register int i = m-1; i >= 0; i--) {
for(register int j = (i == m - 1) ? 1 : 0; j <= d[i] - 1; j++)
ans += DP(i, (pre1 * 10 + j) - (pre1 * 10 + j)/now*now, (pre2 + j));
pre1 = (pre1 * 10 + d[i]);
pre1 -= pre1 / now * now;
pre2 += d[i];
}

for(int i = 1; i <= cnt; i++)
dp[xxx[i]][yyy[i]][zzz[i]] = -1;
ret += ans;
}
return ret;
}
int main() {
int t; scanf("%d", &t);
int cas = 0;
while(t--) {
scanf("%lld", &r);
printf("Case %d: %lld\n", ++cas, calc(r+1));
}
return 0;
}

评论

Your browser is out-of-date!

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

×