zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    Socket
    利用Python自动生成暴力破解的字典
    【转】六年测试工作的思考1
    【转】手机测试入行三年的感想
    【转】移动测试人员的未来:测试开发技术的融合
    【转】一个互联网项目即将结束的软件测试经验总结
    【转】电子商务网站测试经验总结
    【转】六年软件测试感悟-从博彦到VMware
    使用PL/SQL删除百万条记录的大表
    【转】百万级数据查询优化
  • 原文地址:https://www.cnblogs.com/zhixingr/p/8343281.html
Copyright © 2011-2022 走看看