• D. Beautiful numbers(数位DP)


    题目链接:

    https://codeforces.com/contest/55/problem/D

    题目大意:

    给你一个区间,让你求出这个区间里面有多少个数是满足这个数能被 他的所有位上的数 整除的。

    具体思路:

    对于能被他的所有位上的数整除这个条件,转换一下就是这个数能够整除他的所有位上的lcm。

    但是这样的话还是需要求出这个数是谁。因为数的范围比较大,所以就应该考虑取模;

    具体取模的时候,我们可以先算出1~9的lcm,这个是求的过程中的最大的lcm。我们在求这个数是什么的时候,就每次取模1~9的lcm就可以了。

    但是这样的话,这个数组是要dp[19][2520+5][2520+5]这样的话,是会爆内存的。

    然后内存还可以优化一下,这里的第三位表示的是当前的lcm 是多少,这一部分我们是可以预处理出来的,能够被2520整除的只有48个,也就说第三维我们是可以降到50的。

    顺便还学到了一个数位DP的一个巨大的优化,就是对dp赋值的时候,我们没有必要每一次都对他清零。对于这个题,dp[i][j][k]表示前i位,当前的数是多大(mod2520),当前的位数lcm是多少。

    也就是说这里并没有关于首位的标志(如果是开的四位的话,这样复杂度就会优化很小了)。

    AC代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 # define ll long long
     4 # define inf 0x3f3f3f3f
     5 const int maxn = 2e5+100;
     6 const int mod  = 2520;
     7 ll lcm(ll t1,ll t2)
     8 {
     9     return t1/__gcd(t1,t2)*t2;
    10 }
    11 int ord[mod+5];
    12 int tot;
    13 init()
    14 {
    15     for(int i=1; i<=mod; i++)
    16     {
    17         if(mod%i==0)
    18         {
    19             ord[i]=++tot;// 映射
    20         }
    21     }
    22 }
    23 ll dp[20][2530][50];
    24 int a[maxn];
    25 ll dfs(int pos,int sum,int Lcm,int is_head)
    26 {
    27     if(!pos)
    28         return sum%Lcm==0;// 这里有个疑问,假设当前的是 2 * 5 * 8. 如果已经存在 80 这个数,当i==2的时候, 下一次循环是sum==2,然后lcm==10,这样的话是是符合条件的情况,但是对这个代码却不符合 
    29     if(!is_head&&dp[pos][sum][ord[Lcm]]!=-1)
    30         return dp[pos][sum][ord[Lcm]];
    31     int fmax = is_head ? a[pos] : 9;
    32     ll ans=0;
    33     for(int i=0; i<=fmax; i++)
    34     {
    35         ll tmp= ( i==0 ? Lcm : lcm(Lcm,i) );
    36         ans+=dfs(pos-1,(sum*10+i)%mod,tmp,is_head&&i==fmax);
    37     }
    38     if(!is_head)
    39         dp[pos][sum][ord[Lcm]]=ans;
    40     return ans;
    41 }
    42 ll solve(ll n)
    43 {
    44  //   memset(a,0,sizeof(a));
    45     int num=0;
    46     while(n)
    47     {
    48         a[++num]=n%10;
    49         n/=10;
    50     }
    51     
    52     return dfs(num,0,1,1);
    53 }
    54 int main()
    55 {
    56     memset(dp,-1,sizeof(dp));
    57     init();
    58     int T;
    59     scanf("%d",&T);
    60     while(T--)
    61     {
    62         ll l,r;
    63         scanf("%lld %lld",&l,&r);
    64         printf("%lld
    ",solve(r)-solve(l-1));
    65     }
    66     return 0;
    67 }

     

  • 相关阅读:
    不忘初心,方得始终
    【读书笔记】Windows核心编程
    工作心得
    2015年随记
    微信开发的黑魔法
    [cssTopic]浏览器兼容性问题整理 css问题集 ie6常见问题【转】
    获取微信用户openid
    Spring Boot应用开发起步
    一种在Java中跨ClassLoader的方法调用的实现
    H5语义化标签
  • 原文地址:https://www.cnblogs.com/letlifestop/p/11014847.html
Copyright © 2020-2023  润新知