题意
内存限制:256 MiB
时间限制:2000 ms
这些天 nodgd
在研究一类有趣的数。定义函数
f
(
n
)
f(n)
f(n) 表示
n
n
n 在十进制表示下的数字之和。如果一个正整数
n
n
n 满足
f
(
n
)
∣
n
f(n) \vert n
f(n)∣n ,则 nodgd
认为
n
n
n 是有趣的。
例如:
3
3
3,
7
7
7,
12
12
12,
84
84
84,
111
111
111,这些数都是有趣的。显然有趣的数很多,于是 nodgd
想知道不超过
N
N
N 的所有正整数中有多少个是有趣的。
1
≤
N
≤
1
0
18
1 \leq N \leq 10^{18}
1≤N≤1018
题解
不会数位
d
p
dp
dp 快乐
10
10
10 分
设
f
i
,
j
,
k
f_{i,j,k}
fi,j,k 表示前
i
i
i 位,和为
j
j
j ,余数为
k
k
k 的个数
考虑主动转移即可
这个
f
f
f 值计算的是
<
n
<n
<n 的答案
所以当前
i
i
i 位和
n
n
n 相等时,第
i
+
1
i+1
i+1 位只能为
[
0
,
a
i
)
[0,a_i)
[0,ai)
不然可以填
[
0
,
9
]
[0,9]
[0,9]
分讨即可
记得
f
f
f 要清零
#include <bits/stdc++.h>
#define LL long long
LL n,f[20][170][170],ans;
int a[20],t,s[20];
int main(){
scanf("%lld",&n);LL m=n;
while(n) a[++t]=n%10,n/=10;
for (int i=1;i+i<=t;i++) std::swap(a[i],a[t-i+1]);
for (int i=1;i<=t;i++) s[i]=s[i-1]+a[i];
for (int g=1;g<=9*t;g++){
for (int i=1;i<=t;i++)
for (int j=0;j<=9*i && j<=g;j++)
for (int k=0;k<g;k++) f[i][j][k]=0;
for (int d=0,i=0;i<t;i++,d=(10*d+a[i])%g){
for (int j=0;j<=9*i && j<=g;j++)
for (int k=0;k<g;k++)
for (int x=0;x<=9 && j+x<=g;x++)
f[i+1][j+x][(10*k+x)%g]+=f[i][j][k];
for (int x=0;x<a[i+1] && s[i]+x<=g;x++)
f[i+1][s[i]+x][(10*d+x)%g]++;
}
ans+=f[t][g][0];
}
return printf("%lld\n",ans+(m%s[t]==0)),0;
}