Beautiful numbers CodeForces - 55D

原题链接
考察:数位dp
莫得思路,参考大佬的题解(.)
思路:
  1. 整除所有数位的数 == 整除所有数位的lcm
  2. sum%(a*b)%b = sum%b;
  dp方程: f[pos][pre_sum][pre_lcm]+=f[pos-1][pre_sum*10+i][lcm(pre_lcm,i)];
 表示还有pos位未确定,已确定的目前和为pre_sum,lcm为pre_lcm
  用记忆化搜索实现,也有用循环实现的 ----> Go

#include <iostream> 
#include <cstring> 
using namespace std;
typedef long long LL;//1~9的lcm最多48个 
const int N = 20,M = 50,S = 2520;
LL f[N][S][M];
int id[S+5],idx,a[N];
int gcd(int a,int b)
{
	return b?gcd(b,a%b):a;
}
int lcm(int a,int b)
{
	if(!a||!b) return max(a,b);
	return a*b/gcd(a,b);
}
void init()
{
	for(int i=1;i<512;i++)
	{
		int res =1;
		for(int j=0;j<9;j++)
		 if(i>>j&1) res = lcm(res,j+1);
		if(!id[res]) id[res] = ++idx;
	}
}
LL dfs(int pos,int sum,int lcmx,bool limit)
{
	if(!pos) return (sum%lcmx==0);
	if(!limit&&f[pos][sum][id[lcmx]]!=-1) return f[pos][sum][id[lcmx]];
	int up = limit?a[pos]:9; 
	LL res = 0;
	for(int i=0;i<=up;i++)
		res+=dfs(pos-1,(sum*10+i)%S,lcm(lcmx,i),limit&&i==up);
	if(!limit) f[pos][sum][id[lcmx]] = res;
	return res;
}
LL dp(LL n)
{
	if(!n) return 1;
	int cnt = 0;
	while(n) a[++cnt] = n%10,n/=10;
	return dfs(cnt,0,1,1);
}
int main()
{
	int T;
	scanf("%d",&T);
	init();
	memset(f,-1,sizeof f);
	while(T--)
	{
		LL l,r; scanf("%lld%lld",&l,&r);
		printf("%lld\n",dp(r)-dp(l-1));
	}
	return 0;
}
posted @ 2021-05-30 23:43  acmloser  阅读(27)  评论(0编辑  收藏  举报