CodeForces-55D Beautiful numbers(数位DP+离散化)

题意:给定一个区间[a,b],求满足所有非零位都是这个数因数的数的个数。

如果求的是“为7的倍数的数的个数”,那么只用再传参时模7即可。同理,因为非零位只可能是[1,9],我们传参时需要传一个是[1,9]中所有数倍数的数,也就是lcm(1~9),为了判断一种情况是否正确,需要保存出现过的数的lcm,经过验证,总的情况只有48种,故将其离散化保存在dp数组中。

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define FOR(i,x,y) for(int i=(x);i<=(y);i++)
#define DOR(i,x,y) for(int i=(x);i>=(y);i--)
typedef long long LL;
using namespace std;
const int lcm_1_9=2520;
const int kinds=48;
int f[lcm_1_9+3],tot;
LL dp[20][lcm_1_9][kinds+3];
int num[20];
LL gcd(LL x,LL y){return y?gcd(y,x%y):x;}
LL lcm(LL x,LL y){return y?x/gcd(x,y)*y:x;}
void init(int k,int sum)
{
	if(k>9)
	{
		if(!f[sum])f[sum]=++tot;
		return;
	}
	init(k+1,sum);
	init(k+1,lcm(sum,k));
	return;
}
LL dfs(int k,int remainder,int sum,bool ismax)
{
	if(k==0)return !(remainder%sum);
	if(!ismax && ~dp[k][remainder][f[sum]])return dp[k][remainder][f[sum]];
	int maxer=ismax?num[k]:9;
	LL res=0;
	FOR(i,0,maxer)
		res+=dfs(k-1,(remainder*10+i)%lcm_1_9,lcm(sum,i),ismax&&i==maxer);
	if(!ismax)dp[k][remainder][f[sum]]=res;
	return res;
}
LL solve(LL x)
{
	int p=0;
	while(x)
	{
		num[++p]=x%10;
		x/=10;
	}
	return dfs(p,0,1,1);
}
int main()
{
	init(1,1);
	int T;
	scanf("%d",&T);
	memset(dp,-1,sizeof(dp));
	while(T--)
	{
		LL A,B;
		scanf("%lld%lld",&A,&B);
		printf("%lld\n",solve(B)-solve(A-1));
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/paulliant/article/details/80383260