zoukankan      html  css  js  c++  java
  • Beautiful numbers CodeForces

    题意:

    找出区间[li,ri]内有多少数满足,这个数的每一个位的非0数都能把这个数整除

    题解:

    因为这个数每一位的值都可以把这个数整除,那也就是说这个数是它所有位数的公倍数,但是可能不是最小公倍数。

    1、2、3、4、5、6、7、8、9的最小公倍数是2520

    那么我就可以让我们要判断的那个数去取余2520来实现我们记忆化操作

    因为1——9的最小公倍数是2520,所以1——9中任意几个数的最小公倍数肯定是2520的余数,所以我们只需要找出来1——2520之中所有2520的余数就可以了。最后找出来也就48个

    给这48个位置每一个映射一个值

    这个样子就又可以减小dp数组的大小

    dp[x][y][z]表示:枚举到第x位,这个数取余2520的结果是y,这个数目前所有位数的最小公倍数所对应的映射是z

    代码:

     1 //首先要求能被各位上的数整除,可以转化为被一个数整除问题。
     2 //这个数就是各位上数的最小公倍数LCM(不是GCD)。
     3 //其次,处理整除问题,得转化成数位DP的余数模板。1~9的LCM最大是2520, 那么%2520,让其可以开数组进行记忆化搜索。
     4 //最后, 对于不能%2520最后结果,再%各个数位累计过来的LCM。
     5 //这样下来,需要开20*2520*2520的数组,往CF上一交你会发现MLE。
     6 //仔细观察每次的LCM,其范围是1~2520没错,但是都是整除gcd的结果(LCM=a*b/gcd(a,b) ),也就是说所有LCM都是某个数的约数。
     7 //这个数其实就是2520。所以DP之前,为2520打个表,把LCM给离散化Hash。这样其实只有48个LCM了。数组开20*2520*50即可。
     8 //注意结果是int64。
     9 #include<stdio.h>
    10 #include<string.h>
    11 #include<algorithm>
    12 #include<iostream>
    13 #include<map>
    14 using namespace std;
    15 const int maxn=20;
    16 const int mod=2520;
    17 typedef long long ll;
    18 ll v[maxn],dp[maxn][mod+50][50];
    19 map<ll,ll>w;
    20 ll lcm(ll a,ll b)
    21 {
    22     ll ans=min(a,b);
    23     while(ans)
    24     {
    25         if(a%ans==0 && b%ans==0) break;
    26         ans--;
    27     }
    28     return (a*b)/ans;
    29 }
    30 ll dfs(ll pos,ll sum,ll sta,bool limit)
    31 {
    32     if(sta==0)return 0;
    33     if(pos==-1)
    34     {
    35         return sum%sta==0;
    36     }
    37     if(!limit && dp[pos][sum][w[sta]]!=-1) return dp[pos][sum][w[sta]];
    38     ll up=limit?v[pos]:9;
    39     ll tmp=0;
    40     for(ll i=0;i<=up;++i)
    41     {
    42         if(i>0)
    43         {
    44             tmp+=dfs(pos-1,(sum*10+i)%mod,lcm(sta,i),limit && i==v[pos]);
    45 
    46         }
    47         else tmp+=dfs(pos-1,(sum*10+i)%mod,sta,limit && i==v[pos]);
    48     }
    49     if(!limit) dp[pos][sum][w[sta]]=tmp;
    50     //只有上界为9的时候才会往dp数组里面存,因为这样能节省更多的时间
    51     return tmp;
    52 }
    53 ll solve(ll ans)
    54 {
    55     ll pos=0;
    56     while(ans)
    57     {
    58         v[pos++]=ans%10;
    59         ans/=10;
    60     }
    61     return dfs(pos-1,0,1,true);
    62 }
    63 int main()
    64 {
    65     ll t,l,r,m=0;
    66     scanf("%I64d",&t);
    67     for(ll i=1;i<=mod;++i)
    68     {
    69         if(mod%i==0)
    70         {
    71             ++m;
    72             w[i]=m;
    73         }
    74     }
    75     memset(dp,-1,sizeof(dp));
    76     while(t--)
    77     {
    78         scanf("%I64d%I64d",&l,&r);
    79         printf("%I64d
    ",solve(r)-solve(l-1));
    80     }
    81     w.clear();
    82     return 0;
    83 }
  • 相关阅读:
    23岁的这一年
    迁移ORACLE数据库文件到ASM
    无归档情况下使用BBED处理ORA-01113错误
    Oracle RMAN-06023 和ORA-19693错误
    手工创建Oracle数据库
    使用BBED理解和修改Oracle数据块
    Oracle 11g 重建EM需要删除的对象
    各大主流编程语言-常用爬虫框架以及优劣分析
    pyspider入门
    Centos7上安装docker及使用scrapy-splash
  • 原文地址:https://www.cnblogs.com/kongbursi-2292702937/p/11926640.html
Copyright © 2011-2022 走看看