[CodeForces 55D]Beautiful numbers

若一个数n能被它的所有非零数位整除,则n能被它们的最小公倍数x整除

而由1到9中的数组成的最小公倍数最大为2520,且是离散的,实际上只有48个

为了判断这个数能否被它的所有数位整除,我们还需要这个数的值,显然要记录值是不可能的,其实我们只需记录它对2520的模即可

设dp[pos][lcm][mod]表示当前位为pos,前面那些数位的最小公倍数为lcm,前面那些位对2520的模为mod,在用一个flag表示是否达到上限,进行记忆化搜索就好啦

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 #define mod 2520
 5 int tab[]={48,1,2,3,4,5,6,7,8,9,10,12,14,15,18,20,21,24,28,30,35,36,40,42,45,56,60,63,70,72,84,90,105,120,126,140,168,180,210,252,280,315,360,420,504,630,840,1260,2520};
 6 int hsh[2600],dig[20];
 7 ll dp[20][50][2520];
 8 void PP(){
 9     for(int i=1;i<=tab[0];i++)
10         hsh[tab[i]]=i;
11 }
12 int gcd(int a,int b){ return b?gcd(b,a%b):a; }
13 int lcm(int a,int b){ return a*b/gcd(a,b); }
14 ll dfs(int dep,int cur_lcm,int cur_yu,int flag){
15     if(!dep)return cur_yu%tab[cur_lcm]?0:1;
16     if(!flag&&dp[dep][cur_lcm][cur_yu]!=-1)return dp[dep][cur_lcm][cur_yu];
17     int lim=flag?dig[dep]:9;
18     ll ans=0;
19     for(int i=0;i<=lim;i++){
20         int nxt_lcm=i?hsh[lcm(tab[cur_lcm],i)]:cur_lcm;
21         int nxt_yu=(cur_yu*10+i)%mod;
22         ans+=dfs(dep-1,nxt_lcm,nxt_yu,flag&(i==lim));
23     }
24     if(!flag)dp[dep][cur_lcm][cur_yu]=ans;
25     return ans;
26 }
27 ll solve(ll x){
28     int dd=0;
29     while(x)dig[++dd]=x%10,x/=10;
30     return dfs(dd,1,0,1);
31 }
32 int main(){
33     PP();
34     int T;
35     scanf("%d",&T);
36     memset(dp,-1,sizeof(dp));
37     while(T--){
38         ll A,B;
39         scanf("%lld%lld",&A,&B);
40         printf("%lld
",solve(B)-solve(A-1));
41     }
42     return 0;
43 }
View Code
原文地址:https://www.cnblogs.com/Ngshily/p/5481981.html