题目链接:https://cn.vjudge.net/contest/194559#problem/R
此题开创了我对数位dp理解的新纪元
题目大意:一个最大为18位的整数,判断他是否能够整除自己各个位数的和。
分析:这么长的数字只能用状态压缩,但由于是否能够被mod整除,可能每次mod都会变化,就用暴力依次找寻,又因为每个位上的数字最大为9,最多18位,所以9*18便是最大的mod,最后判断的时候就判断所有位数的和是否为mod,并且余数是否为0,两个条件满足了就是了。(实现判断所有位数的和是否为mod的方法:其中sum的初值设为mod,每往下一位找寻时就减掉前一位i,最后判断sum是否为0.)
具体代码如下:
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
typedef long long ll;
ll dp[25][163][163][2];
ll dig[25];
ll dfs(int pos,int sum,int k,int mod,int limit)
{
if(pos==0)
return k==0&&sum==0;
if(dp[pos][sum][k][limit]!=-1)
return dp[pos][sum][k][limit];
ll ans=0;
int up=limit?dig[pos]:9;
for(int i=0;i<=up;i++)
{
if(sum-i<0)
break;
ans+=dfs(pos-1,sum-i,(k*10+i)%mod,mod,limit&&i==up);
}
dp[pos][sum][k][limit]=ans;
return ans;
}
ll solve(ll x)
{
int pos=0;
while(x)
{
dig[++pos]=x%10;
x/=10;
}
ll ans=0;
for(int mod=1;mod<=pos*9;mod++)
{
memset(dp,-1,sizeof(dp));
ans+=dfs(pos,mod,0,mod,1);
}
return ans;
}
int main()
{
ll n,m;
while(~scanf("%lld%lld",&n,&m))
{
printf("%lld\n",solve(m)-solve(n-1));
}
return 0;
}