• Codeforces 55D Beautiful numbers 数位dp


    题目地址:http://codeforces.com/problemset/problem/55/D

    若一个数字n能被它数位上的每一个非零数字整除,称这个数为Beautiful number。

    问给定区间[l, r]内有多少个Beautiful numbers。

    1≤l≤r≤9*1e18

    很明显的数位dp。

    我觉着数位dp其实就是记忆化搜索的一种使用形式。

    dfs统计小于x的Beautiful numbers的数目。

    搜索过程中传递4个信息:当前位pos,搜索路径上的数字组成的数值(比如说1->3->5那么就是135),搜索路径上的数字的最小公倍数,和一个用于标志最高位应当是9还是x[pos]的flag

    观察到1-9的最小公倍数为2520,1-9中数的组合的最小公倍数只有48个。于是传递数值的时候只需传递值%2520,最小公倍数的编号。

    从而不同的状态数数目不超过[20][2520][48]。

    AC代码:

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;++i)
    long long l,r;
    int bit[20];
    long long dp[20][2520][50];
    int fact[50];
    int cnt;
    void init()
    {
        memset(dp,-1,sizeof(dp));
    }
    int gcd(int a,int b)
    {
        return b==0?a:gcd(b,a%b);
    }
    int lcm(int a,int b)
    {
        return a*b/gcd(a,b);
    }
    void pre()
    {
        cnt=0;
        rep(i,1,2520)
        {
            if(2520%i==0) fact[++cnt]=i;
        }
    }
    int searchnum(int x)
    {
        int l=1,r=cnt;
        while(l<r)
        {
            int mid=(l+r)>>1;
            if(x<=fact[mid]) r=mid;
            else l=mid+1;
        }
        //printf("l=%d x=%d fact[]=%d
    ",l,x,fact[l]);
        return l;
    }
    long long dfs(int pos,int mod,int prelcm,int flag)
    {
        if(pos==-1)
        {
            if(mod%fact[prelcm]==0) return 1;
            else return 0;
        }
        if(!flag&&dp[pos][mod][prelcm]!=-1) return dp[pos][mod][prelcm];
        int endbit=flag?bit[pos]:9;
        long long res=0;
        int nowlcm=prelcm;
        rep(i,0,endbit)
        {
            if(i)
            {
                nowlcm=searchnum(lcm(i,fact[prelcm]));
            }
            res+=dfs(pos-1,(mod*10+i)%2520,nowlcm,flag&&(i==endbit));
        }
        if(!flag) dp[pos][mod][prelcm]=res;
        return res;
    
    }
    long long calc(long long x)
    {
        int len=0;
        while(x)
        {
            bit[len++]=x%10;
            x/=10;
        }
        return dfs(len-1,0,1,1);
    }
    int main()
    {
        int TT;scanf("%d",&TT);
        init();
        pre();
        rep(t1,1,TT)
        {
            scanf("%I64d%I64d",&l,&r);
            printf("%I64d
    ",calc(r)-calc(l-1));
        }
        return 0;
    }
  • 相关阅读:
    javaScript中eval()方法转换json对象
    JS 根据参数是否为空进行true|false判断呢
    mybatis返回map类型数据空值字段不显示(三种解决方法)
    值类型与引用类型的区别
    随机生成四位数字和字母
    彩票
    冒泡排序
    查询资料:二分查找法
    随机数生成机制
    运算符
  • 原文地址:https://www.cnblogs.com/zhixingr/p/8343281.html
Copyright © 2020-2023  润新知