CodeForces 55D Beautiful numbers

本文介绍了一种使用数位动态规划解决 Beautiful Number 问题的方法。Beautiful Number 定义为能被其所有非零位整除的数字。文章详细阐述了如何通过状态压缩和优化减少空间复杂度,并给出了 AC 代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

         题意:求[l,r]内beautiful number的数量,如果一个数字能够整除它所有非零位那么它是beautiful number。

         首先推荐一个重要的结论sum%(n*x)%(x)==sum%x(n为正整数)。

        其实感觉对于这个题来说,就是一个暴力。我们首先从暴力考虑,我们直接dfs状态肯定是(pos,now,lcm,isin),表示加数字到pos位了,现在加成的数字是什么,它的lcm是多少,是否在边界上。转移就是每次添加一个数字,每次添加一个数字。那么数位dp就是总结各个位置上的规律与共性,共性是什么呢,就要用上面的结论了。

        由于我们的边界是处理到最后(now%lcm==0)则答案是1,那么我们如果从now入手,我们值关心now取模之后的答案,所以借用上面的结论sum%(n*x)%(x)==sum%x,我们只需找到一个合适的(n*x)使得其对于所有模数都满足结论即可,那最小就是所有x即lcm的gcd,为2520了。

        所以我们就可将dp[i][j][k]定义为处理到第i位,lcm为j,now%2520为k的方案数了,可是这样会爆空间,考虑到j即lcm的数值并不是全部连续的,1-9的不同组合lcm就只有50种以内,所以多开一个数组rev[i]表示i这个lcm是第几大的进行离散化即可。

        下附AC代码

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define maxn 23
using namespace std;
typedef long long ll;
const int mod=2520;
ll l,r;
int cnt,tot;
int bit[maxn];
int rev[2550];
ll dp[maxn][50][2550];
ll gcd(ll x,ll y)
{
	return y==0 ? x:gcd(y,x%y);
} 
ll lcm(ll x,ll y)
{
	return x/gcd(x,y)*y;
}
ll dfs(ll pos,ll now,ll nowlcm,int isin)
{
	if(!pos)  return (now%nowlcm==0);
	if(!isin && dp[pos][rev[nowlcm]][now]!=-1) return dp[pos][rev[nowlcm]][now];
	int maxx=isin?bit[pos]:9;
	ll ans=0;
	for(int i=0;i<=maxx;i++)
	{
		ll nexlcm=(i==0?nowlcm:lcm(nowlcm,(ll)i));
		ans+=dfs(pos-1,((now*10+i)%mod),nexlcm,isin&&i==maxx);
	}
	if(!isin) dp[pos][rev[nowlcm]][now]=ans;
	return ans;
}
ll solve(ll now)
{
	tot=0;
	while(now)
	{
		bit[++tot]=now%10;
		now/=10;
	}
	return dfs(tot,0,1,1);
}
int main()
{
	for(int i=1;i<=mod;i++)
	if(mod%i==0)
	rev[i]=++cnt;
	memset(dp,-1,sizeof(dp)); 
	int _;
	scanf("%d",&_);
	while(_--)
	{
		scanf("%I64d%I64d",&l,&r);
		printf("%I64d\n",solve(r)-solve(l-1));
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值