zoukankan      html  css  js  c++  java
  • CF55D

    题目大意:

      定义:beautiful number,一种能整除它的所有非 0 数位的数字。

      给你 l 和 r,请求出 [l,r] 中 beautiful number 的个数。

    解题思路:

      数位 DP 。

      首先要指出的一点是:lcm(1,2,3, ... ,9) = 2520。则对于任何一个数 num,num = 2520k + num',我们有 num % 2520 % t = num' % t = num % t (t = 1,2,3, ... , 9),其实也不难理解:因为 2520k 必定被 t 整除,所以 num % t 其实就等于 num' % t 。下面是一个就 t % (x*n) % x = t % x 的严格证明:

      设 t = k*x + t' 。则有 t%x = t' 。令 k = a*n+b,则 t % (x*n) % x = (k*x+t') % (x*n) % x = (a*n*x + b*x + t') % (n*x) % x = (b*x + t') % x = t' 。原等式得证。

      如此一来,我们便可将所有的数字对着 2520 取一下模,压缩状态。

      我们可以定义 dp[pos][now][prelcm]:其中 pos 表示当前遍历到的位置,now 表示当前数字的大小,prelcm 表示前面的几个数字的最小公倍数,如此我们需要定义 dp[20][2520][2521],虽然已经十分优秀,但似乎还有点大?其实我们还可以用离散化来优化一下:虽说 lcm(1,2,3, ... ,9) = 2520,但我们绝对不可能取尽这两千多个数,你说对吧?

      至于其他的,其实就都是套路了,数位 DP 其实也是有套路滴~

    AC代码:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 
     5 using namespace std;
     6 typedef long long ll;
     7 const int MOD = 2520;
     8 ll index[MOD+3];
     9 ll dp[22][MOD][50];
    10 int num[20];
    11 void init(){
    12     int cnt=0;
    13     for(int i=1;i<=MOD;i++){
    14         if(MOD%i==0)    index[i]=cnt++;
    15     }
    16 }
    17 ll gcd(ll a,ll b){
    18     if(b==0)    return a;
    19     return gcd(b,a%b);
    20 }
    21 ll lcm(ll a,ll b){
    22     return a/gcd(a,b)*b;
    23 }
    24 ll dfs(int pos,int prelcm,int now,bool limit){
    25     if(pos==-1){
    26         if(now%prelcm==0)  return 1;
    27         return 0;
    28     }
    29     if(!limit&&dp[pos][now][index[prelcm]]!=-1)    return dp[pos][now][index[prelcm]];
    30     int up=limit?num[pos]:9;
    31     ll ret=0;
    32     for(int i=0;i<=up;i++){
    33         int next=(now*10+i)%MOD;
    34         int tlcm=prelcm;
    35         if(i)   tlcm=lcm(tlcm,i);
    36         ret+=dfs(pos-1,tlcm,next,limit&&i==up);
    37     }
    38     if(!limit)  dp[pos][now][index[prelcm]]=ret;
    39     return ret;
    40 }
    41 ll solve(ll x){
    42     if(x==0)    return 1;
    43     int ind=0;
    44     memset(num,0,sizeof(num));
    45     while(x){
    46         num[ind++]=x%10;
    47         x/=10;
    48     }
    49     return dfs(ind-1,1,0,true);
    50 }
    51 int main()
    52 {
    53     init();
    54     memset(dp,-1,sizeof(dp));
    55     ll l,r;
    56     int t;
    57     scanf("%d",&t);
    58 
    59     while(t--){
    60         scanf("%I64d%I64d",&l,&r);
    61         printf("%I64d
    ",solve(r)-solve(l-1));
    62     }
    63     return 0;
    64 }

      

    “这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。”
  • 相关阅读:
    自定义能够for each的类,C#,Java,C++,C++/cli的实现方法
    答网友强护灰飞烟灭关于接口的问题
    浅谈C++的this指针
    padding与margin的区别(网上转的)
    啦啦啦 刚注册的,先水一篇~
    直接把页面的table导出到excel表中
    从FTP下载文件带进度条
    C# 从FTP上下载指定文件到本机
    “无法在证书存储区中找到清单签名证书”错误的解决方法
    网页设置不可复制
  • 原文地址:https://www.cnblogs.com/Blogggggg/p/7764023.html
Copyright © 2011-2022 走看看