Description
给出a,b,求出[a,b]中各位数字之和能整除原数的数的个数。
Input
Output
Sample Input
10 19
Sample Output
3
HINT
【约束条件】1 ≤ a ≤ b ≤ 10^18
题解:
枚举模数p.
设f[i][j][k][g]表示第i位,前i位的和为j,当前模p的值为k,到第i位是否比原数小.
枚举所有状态向后转移即可.
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
ll pow[20],f[20][200][200][2],l,r;
int p[20],num,mx;
ll cal(ll x){
ll ans=0;mx=0;num=0;
while (x){p[++num]=x%10;x/=10;}
for (int i=1;i<=num/2;i++) swap(p[i],p[num-i+1]);
for (int i=1;i<=num;i++) mx+=9;
for (int md=1;md<=mx;md++){
memset(f,0,sizeof(f));
f[0][0][0][1]=1;
for (int i=0;i<num;i++)
for (int j=0;j<=md;j++)
for (int k=0;k<md;k++)
for (int g=0;g<=1;g++)
if (f[i][j][k][g])
for (int a=0;a<=9;a++){
int x,y,z;
if (g&&a>p[i+1]) continue;
x=j+a;y=(k+(pow[num-(i+1)]%(ll)md)*a%md)%md;
z=(g&&(a==p[i+1]))?1:0;
f[i+1][x][y][z]+=f[i][j][k][g];
}
ans+=f[num][md][0][0]+f[num][md][0][1];
}
return ans;
}
int main(){
pow[0]=1;
for (int i=1;i<=18;i++) pow[i]=pow[i-1]*(ll)10;
scanf("%lld%lld",&l,&r);
printf("%lld\n",cal(r)-cal(l-1));
}