zoukankan      html  css  js  c++  java
  • Codeforces 55D. Beautiful numbers (数位DP)

    题意:求区间[x , y]中beautiful number的个数,a positive integer number is beautiful if and only if it is divisible by each of its nonzero digits.

    分析:一个数能被它的所有非零数位整除,则能被它们的最小公倍数整除,而1到9的最小公倍数为2520,数位DP时我们只需保存前面那些位的最小公倍数就可进行状态转移,到边界时就把所有位的lcm求出了,为了判断这个数能否被它的所有数位整除,我们还需要这个数的值,显然要记录值是不可能的,其实我们只需记录它对2520的模即可,这样我们就可以设计出如下数位DP:dfs(pos,mod,lcm,f),pos为当前位,mod为前面那些位对2520的模,lcm为前面那些数位的最小公倍数,f标记前面那些位是否达到上限,这样一来dp数组就要开到19*2520*2520,明显超内存了,考虑到最小公倍数是离散的,1-2520中可能是最小公倍数的其实只有48个,经过离散化处理后,dp数组的最后一维可以降到48,这样就不会超了。

    View Code
    #include <stdio.h>
    #include <string.h>
    #define N 19
    #define MOD 2520
    typedef __int64 LL;
    int t[200],cnt;
    LL dp[N][MOD][48];
    int digit[N];
    int GCD(int a,int b)
    {
        while(a%b)
        {
            int tmp=b;
            b=a%b;
            a=tmp;
        }
        return b;
    }
    int LCM(int a,int b)
    {
        return a/GCD(a,b)*b;
    }
    int bs(int x)
    {
        int mid,min=0,max=cnt;
        while(min+1!=max)
        {
            mid=min+max>>1;
            if(t[mid]>x)    max=mid;
            else    min=mid;
        }
        return min;
    }
    LL dfs(int pos,int mod,int lcmid,int f)
    {
        if(pos==-1) return (mod%t[lcmid])?0:1;
        if(!f&&dp[pos][mod][lcmid]!=-1)   return dp[pos][mod][lcmid];
        int max=f?digit[pos]:9;
        LL ret=0;
        for(int i=0;i<=max;i++)
        {
            int nmod=(mod*10+i)%MOD;
            int nlcmid=lcmid;
            if(i)   nlcmid=bs(LCM(t[lcmid],i));
            ret+=dfs(pos-1,nmod,nlcmid,f&&i==max);
        }
        if(!f)  dp[pos][mod][lcmid]=ret;
        return ret;
    }
    LL cal(LL x)
    {
        int pos=0;
        while(x)
        {
            digit[pos++]=x%10;
            x/=10;
        }
        return dfs(pos-1,0,0,1);
    }
    void init()
    {
        cnt=0;
        for(int i=1;i<=MOD;i++)
        {
            if(MOD%i==0)    t[cnt++]=i;
        }
        memset(dp,-1,sizeof(dp));
    }
    int main()
    {
        int t;
        init();
        scanf("%d",&t);
        while(t--)
        {
            LL x,y;
            scanf("%I64d%I64d",&x,&y);
            printf("%I64d\n",cal(y)-cal(x-1));
        }
        return 0;
    }
  • 相关阅读:
    一周精彩内容分享(第 5 期):货拉拉悲剧的背后
    关于 HTTP 后端人员需要了解的 20+ 图片!
    百度地图午夜暗蓝风格
    百度地图开发自定义信息窗口openInfoWindow样式
    百度地图infowindow上添加自定义点击事件
    js显示当前日期时间和星期几
    iview 树形异步加载,首次加载子节点不能选择,点击父节点后才可以选择
    js 修改属性名和值。并只保留需要的属性
    css 条形百分比
    echarts 3d饼图
  • 原文地址:https://www.cnblogs.com/algorithms/p/2668021.html
Copyright © 2011-2022 走看看