1799: [Ahoi2009]self 同类分布
Time Limit: 50 Sec Memory Limit: 64 MB
Submit: 1883 Solved: 843
[Submit][Status][Discuss]
Description
给出a,b,求出[a,b]中各位数字之和能整除原数的数的个数。
Input
Output
Sample Input
10 19
Sample Output
3
HINT
【约束条件】1 ≤ a ≤ b ≤ 10^18
Source
非常裸的一个数位dp。令dp[len][sum][mod][r]表示长度为len的数字,当前已经有各位数字的和为sum,最后各位数字和为mod,当前数值对mod取模结果为r时的方案数。根据数据范围,我们发现,如果按照这样子开成四维,空间会炸。但是,在实际操作的时候,我们可以通过枚举固定的mod来少掉一维。
接下来考虑转移方程,,其中sum>i。退出条件的话,当len==0时,当然要求sum要用完等于0,同时余数要为0。按照普通数位dp记忆化搜索的套路去做即可。具体见代码:
#include<bits/stdc++.h>
#define LL long long
using namespace std;
LL dp[20][163][163],ten[19];
int num[20],tot,mod;
LL dfs(int len,int sum,LL r,bool lim)
{
if (len==0) return sum==0&&r==0;
if (!lim&&~dp[len][sum][r]) return dp[len][sum][r];
int up=lim?num[len]:9; LL res=0;
for(int i=0;i<=up;i++)
{
if (sum<i) break;
res+=dfs(len-1,sum-i,(r*10+i)%mod,lim&&i==up);
}
if (!lim) dp[len][sum][r]=res;
return res;
}
LL cal(LL x)
{
tot=0;
if (x==0) return 0;
while(x)
{
num[++tot]=x%10;
x/=10;
}
LL res=0;
for(int i=1;i<=9*tot;i++)
{
memset(dp,-1,sizeof(dp));
mod=i; res+=dfs(tot,i,0,1);
}
return res;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0); LL n,m;
ten[0]=1;
for(int i=1;i<=18;i++)
ten[i]=ten[i-1]*10LL;
while(cin>>n>>m)
{
cout<<cal(m)-cal(n-1)<<endl;
}
return 0;
}