Beautiful numbers

​CodeForces - 55D ​

题意:给出t个样例,每样例给出L和R问在L和R中间有多少数为漂亮数,漂亮数的定义为:数里面的每一位都可以被该数整除。

思路:数位dp,首先将数分解为位数,然后进行dfs搜索。对于dfs里面每一位参数以作解释了。对于dp,2520是1-9的最小公倍数。50是1-2520里面有多少是2520的因数。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
int p[20],hash0[2520+10];
ll dp[20][50][2520+10];
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
ll dfs(int len,int lcm,int num,bool flag){//len 代表当前到了哪一位,lcm 表示该数的所有最小公倍数,num 表示该数,flag判断是不是边界
ll ans=0;
if(len==-1) return num%lcm?0:1;
int hlcm=hash0[lcm];
if(!flag&&dp[len][hlcm][num]!=-1) return dp[len][hlcm][num];
int end=flag?p[len]:9;
for(int i=0;i<=end;i++){
ans+=dfs(len-1,i?i/gcd(i,lcm)*lcm:lcm,(num*10+i)%2520,flag&&i==end);
}
if(!flag) dp[len][hlcm][num]=ans;
return ans;
}
ll solve(ll n){
int len=0;
while(n){
p[len++]=n%10;
n/=10;
}
return dfs(len-1,1,0,true);
}
int main(){
int cnt=0;
memset(dp,-1,sizeof(dp));
for(int i=1;i<=2520;i++){
if(2520%i==0) hash0[i]=cnt++;
}
ll t,l,r;
cin>>t;
while(t--){
cin>>l>>r;
cout<<solve(r)-solve(l-1)<<endl;
}
return 0;
}