【题目】
题目描述:
给出两个数 a , b a,b a,b,求出 [    a   , b    ] [\;a\,,b\;] [a,b] 中各位数字之和能整除原数的数的个数。
输入格式:
一行,两个整数 a a a 和 b b b。
输出格式:
一个整数,表示答案。
样例数据:
输入
10 19
输出
3
说明:
对于所有的数据, 1 ≤ a ≤ b ≤ 1 0 18 1 ≤ a ≤ b ≤ 10^{18} 1≤a≤b≤1018。
【分析】
一道比较妙的数位 D P \mathrm{DP} DP题。
我们最后要求的相当于这个数模 “ “ “各位数字之和 ” ” ”的结果,但这个 “ “ “各位数字之和 ” ” ”在 d p dp dp 的时候是在变的,不能统计出这个数模它的结果,那该怎么办呢?
答案是枚举!我们可以枚举每个数字之和的值,在统计的时候判断一下总和是否等于这个值就好了。
然后把每个枚举值的答案加起来就是最终的答案啦。
【代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
int Mod,a[25];
ll f[25][165][165][2];
ll dp(int p,int sum,int m,bool limit)
{
if(!p) return (sum==Mod)&&(!m);
if(~f[p][sum][m][limit]) return f[p][sum][m][limit];
int i,up=limit?a[p]:9;ll ans=0;
for(i=0;i<=up;++i)
ans+=dp(p-1,sum+i,(m*10+i)%Mod,limit&&a[p]==i);
return f[p][sum][m][limit]=ans;
}
ll solve(ll x)
{
int p=0;ll ans=0;
while(x) a[++p]=x%10,x/=10;
for(Mod=1;Mod<=9*p;++Mod)
{
memset(f,-1,sizeof(f));
ans+=dp(p,0,0,true);
}
return ans;
}
int main()
{
ll l,r;
scanf("%lld%lld",&l,&r);
printf("%lld",solve(r)-solve(l-1));
return 0;
}