版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Rose_max/article/details/81673682
Description
给出a,b,求出[a,b]中各位数字之和能整除原数的数的个数。
Input
Output
Sample Input
10 19
Sample Output
3
HINT
【约束条件】1 ≤ a ≤ b ≤ 10^18
题解
明明很水我做了这么久..真是失了智
容易发现模数不会大于9*18
容易发现总和不会大于9*18
我们枚举模数,记忆化搜索数位dp
分别是
当前位置 当前余数 当前模数 当前剩余数的和 前面的位数是否顶上界
裸着跑就好了…
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#define LL long long
using namespace std;
LL l,r,pre[20];
int num[20],ln;
void gt(LL p)
{
ln=0;
while(p)num[++ln]=p%10,p/=10;
}
LL f[20][170][170][2];
int gg[20][170][170][2],tim;
LL dp(int pos,int ux,int md,int sum,int op)//位置 余数 模数 剩下的 顶上界
{
if(sum<0)return 0;
if(pos<=0)
{
if(ux==0&&sum==0)return 1;
return 0;
}
if(gg[pos][ux][sum][op]==tim)return f[pos][ux][sum][op];
LL s=0;
if(op==1)//顶上界
{
s=s+dp(pos-1,(ux-num[pos]*pre[pos]%md+md)%md,md,sum-num[pos],1);//顶上界
for(int i=0;i<num[pos];i++)
s=s+dp(pos-1,(ux-i*pre[pos]%md+md)%md,md,sum-i,0);
}
else
{
for(int i=0;i<=9;i++)
{
// printf("%lld\n",dp(pos-1,(ux-i*pre[pos]%md+md)%md,md,sum-i,0));
s=s+dp(pos-1,(ux-i*pre[pos]%md+md)%md,md,sum-i,0);
}
}
gg[pos][ux][sum][op]=tim;f[pos][ux][sum][op]=s;
return s;
}
LL S(LL p)
{
LL ret=0;
gt(p);
for(int i=1;i<=9*ln;i++)
tim++,ret+=dp(ln,0,i,i,1);
return ret;
}
int main()
{
pre[1]=1;for(int i=2;i<=18;i++)pre[i]=pre[i-1]*10;
scanf("%lld%lld",&l,&r);
printf("%lld\n",S(r)-S(l-1));
return 0;
}