数位dp专题之Beautiful numbers
Posted yeah17981
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数位dp专题之Beautiful numbers相关的知识,希望对你有一定的参考价值。
持续更新中……
Beautiful numbers
数位dp之dp手的折戟
我真的好讨厌写dfs啊
dp?dfs!
幸好还是做出了一道,不然就真罚座一晚上了。
给t组查询,求l到r之间有多少个数字,满足其每一位数都是其因子
首先找到1-9的最小公倍数为2520,它的48个因子分别对应的是1-9不同组合下的最小公倍数。通过离散化把48个因子标序1-48
再者,因为需要进行状态的转移,在记录数字铁定会爆的情况下我们选择记录对2520取模后的结果,通过对余数的处理进行转移。
看这数字肯定不能暴力捏,但是结果和位数存在关系,考虑枚举位数,并且记录此时是否达到上限。
而余数*10+位数可能性为新的余数,由此进行动态转移
设dp[j][i][k],当前位为j,余数为i,最小公倍数ak下的ans
dfs(pos,presum,prelcm,flag) 分别为 当前位数,当前余数,当前lcm,是否达到上限
其余的看看代码吧
//给n个范围,求区间内符合条件的元素个数
//如果是2520的倍数一符合条件 如果不是,看余数
//dp[j][i][k] 当前位为j,余数为i,最小公倍数ak下的ans
#include<bits/stdc++.h>
using namespace std;
const long long mod=2520;
long long a[mod];
long long num1[25];
long long dp[10][2520][48];
void _init_()//预处理出所有因数和id的关系
long long cnt=0;
for(long long i=1;i<=mod;i++)
if(mod%i==0) a[i]=cnt++;
long long lcm(long long a,long long b)//求lcm
return a/__gcd(a,b)*b;
long long dfs(long long pos,long long presum,long long prelcm,bool flag)//从高位向低位枚举
if(pos==-1) return presum%prelcm==0;//所有位数都枚举过了
if(!flag&&dp[pos][presum][a[prelcm]]!=-1)//已达上限且已经算过了
return dp[pos][presum][a[prelcm]];
long long ans=0;
long long end = flag ? num1[pos] : 9;//没到上限就取上限,到了就取9
for (long long i = 0; i <= end; i++)
long long nowSum = (presum * 10 + i) % mod;//处理余数
long long nowLcm = prelcm;
if (i)
nowLcm = lcm(nowLcm, i);//更新lcm
ans += dfs(pos - 1, nowSum, nowLcm, flag && i == end);
if (!flag) //已达上限但是没算过
dp[pos][presum][a[prelcm]] = ans;
return ans;
long long calc(long long x)
long long cnt=0,n=x;
while(n>0)
num1[cnt++]=n%10;
n/=10;
return dfs(cnt-1,0,1,1);
int main()
_init_();
memset(dp, -1, sizeof(dp));
long long _,l,r;
cin>>_;
while(_--)
cin>>l>>r;
cout<<calc(r)-calc(l-1)<<"\\n";
大致就这样吧我困了我真的不会我要去吃夜宵了qaq
以上是关于数位dp专题之Beautiful numbers的主要内容,如果未能解决你的问题,请参考以下文章
CodeForces 55D Beautiful numbers(数位dp&&离散化)
CodeForces - 55D Beautiful numbers (数位DP)
CodeForces 55D - Beautiful numbers - [数位DP+离散化]