题目
给出两个数 a , b a,b a,b,求出 [ a , b ] [a,b] [a,b]中各位数字之和能整除原数的数的个数。
分析
设
f
[
i
]
[
s
]
[
m
]
[
0
/
1
]
为
前
i
位
,
和
为
s
,
这
个
数
m
o
d
  
s
u
m
=
m
,
0
表
示
没
卡
上
界
,
1
表
示
卡
了
上
界
。
设f[i][s][m][0/1]为前i位,和为s,这个数\mod sum=m,0表示没卡上界,1表示卡了上界。
设f[i][s][m][0/1]为前i位,和为s,这个数modsum=m,0表示没卡上界,1表示卡了上界。
f
[
i
+
1
]
[
s
+
k
]
[
(
m
∗
10
+
k
)
m
o
d
  
s
u
m
]
[
c
按
位
与
(
k
=
=
t
[
i
]
)
]
+
=
f
[
i
]
[
s
]
[
m
]
[
c
]
;
f[i+1][s+k][(m*10+k)\mod sum][c按位与(k==t[i])]+=f[i][s][m][c];
f[i+1][s+k][(m∗10+k)modsum][c按位与(k==t[i])]+=f[i][s][m][c];
然后其实得到这个最后答案为
f
[
n
]
[
s
u
m
]
[
0
]
[
0
]
+
f
[
n
]
[
s
u
m
]
[
0
]
[
1
]
f[n][sum][0][0]+f[n][sum][0][1]
f[n][sum][0][0]+f[n][sum][0][1],然后卡卡常就没什么了
代码(自行卡常)
#include <cstdio>
#include <algorithm>
#include <cstring>
typedef unsigned long long ull;
ull a,b,f[2][181][181][2];
ull answer(ull x){
ull X=x; int t[21],n=0;
while (X) t[++n]=X%10,X/=10;
std::reverse(t+1,t+1+n); ull ans=0;
for (register int sum=1;sum<=n*9;sum++){
memset(f[0],0,sizeof(f[0])); bool x=0;
f[0][0][0][1]=1;
for (register int i=0;i<n;i++){
x^=1; memset(f[x],0,sizeof(f[x]));
for (register int s=0;s<=sum;s++)
for (register int m=0;m<sum;m++)
for (register int c=0;c<2;c++){
long long res=f[x^1][s][m][c];
if (!res) continue;//得不到答案
for (register int k=0;k<=(c?t[i+1]:9);k++){
if (s+k>sum) break;
else f[x][s+k][(m*10+k)%sum][c&(k==t[i+1])]+=res;
}
}
}
ans+=f[x][sum][0][0]+f[x][sum][0][1];
}
return ans;
}
int main(){
scanf("%llu%llu",&a,&b);
return !printf("%llu",answer(b)-answer(a-1));//前缀和
}