Written with StackEdit.\

Description

给出\(a,b\),求出\([a,b]\)中各位数字之和能整除原数的数的个数。

Input

一行两个正整数,\(a,b\).

Output

\([a,b]\)中各位数字之和能整除原数的数的个数.

Sample Input

10 19

Sample Output

3

HINT

\(1 ≤ a ≤ b ≤ 10^{18}\).

Solution

  • 显然是一道数位\(dp\).
  • 但这道题需要注意,计算前需要先确定模数,即数位总和,否则算出来的\(f\)值是在不同模数下的\(f\),无法转移.
  • 注意到数位和最大为\(9*18=162\),所以从\(1\)\(162\)依次枚举数位和,进行数位\(dp\)即可.只需注意最后的时候验证数位和是否为枚举的数位和即可.
#include<bits/stdc++.h>
using namespace std;
typedef long long LoveLive;
inline LoveLive read()
{
	LoveLive out=0,fh=1;
	char jp=getchar();
	while ((jp>'9'||jp<'0')&&jp!='-')
		jp=getchar();
	if (jp=='-')
		{
			fh=-1;
			jp=getchar();
		}
	while (jp>='0'&&jp<='9')
		{
			out=out*10+jp-'0';
			jp=getchar();
		}
	return out*fh;
}
const int MAXSUM=162;
int n;
int t[20];
void split(LoveLive x)
{
	n=0;
	while(x)
		{
			t[++n]=x%10;
			x/=10;
		}
}
LoveLive f[20][200][200];
LoveLive dfs(int dep,int r,int sum,int mod,int limit)
{	
	if(dep==0)
		{
			if(r==0 && sum==mod)
				return 1;
			else
				return 0;
		}
	if(sum>mod)//可行性剪枝,其实还有其他剪枝,太懒没有打
		return 0;
	if(!limit && f[dep][r][sum]!=-1)
		return f[dep][r][sum];
	LoveLive res=0;
	int mx=limit?t[dep]:9;
	for(int i=0;i<=mx;++i)
		res+=dfs(dep-1,(10*r+i)%mod,sum+i,mod,limit && i==mx);
	if(!limit)
		f[dep][r][sum]=res;
	return res; 
}
LoveLive solve(LoveLive x)
{
	LoveLive res=0;
	split(x);
	for(int mod=1;mod<=MAXSUM;++mod)
		{
			memset(f,-1,sizeof f);
			res+=dfs(n,0,0,mod,1);
		}
	return res;
}
int main()
{
	LoveLive ans=0;
	LoveLive L=read(),R=read();
	ans+=solve(R);
	ans-=solve(L-1);
	printf("%lld\n",ans);
	return 0;
}

相关文章:

  • 2021-06-20
  • 2022-01-07
  • 2021-11-13
  • 2021-10-29
  • 2022-12-23
  • 2022-12-23
  • 2021-10-20
  • 2022-02-04
猜你喜欢
  • 2022-02-20
  • 2022-01-24
  • 2021-06-24
  • 2021-09-16
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案