Codeforces Beta Round #51 D. Beautiful numbers

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

题意:

询问[l,r]内有多少个数字,满足能被自己的每一位非0数整除

数位DP

表示出当前对2520取模的余数,以及目前各个数位数字的最小公倍数

因为0—9的最小公倍数是2520,而且最小公倍数只有48种情况

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
     
    using namespace std;
     
    typedef long long LL;
     
    const int mod=2520;
     
    int num[21];
    int lcm[11][2525],li[2525],il[51],sl;
    LL dp[21][2525][51];
     
    LL dfs(int dep,bool lim,int r,int lc)
    {    
        if(!lim && dp[dep][r][li[lc]]!=-1) return dp[dep][r][li[lc]];
        if(!dep) return !(r%lc);
        bool nlim;
        int nr,nlcm;
        LL sum=0;
        int up=lim ? num[dep] : 9;
        for(int i=0;i<=up;++i)
        {
            nlim=(lim && i==num[dep]);
            nr=(r*10+i)%mod;
            nlcm=lcm[i][lc];
            sum+=dfs(dep-1,nlim,nr,nlcm);
        }
        if(!lim) dp[dep][r][li[lc]]=sum;
        return sum;
    }
     
    LL solve(LL n)
    {
        int m=0;
        while(n) num[++m]=n%10,n/=10;
        return dfs(m,1,0,1);
    }
     
    void pre()
    {
        for(int i=0;i<=9;++i)
            for(int j=1;j<=mod;++j)
            {
                if(!i) lcm[i][j]=j; 
                else lcm[i][j]=i*j/__gcd(i,j);
            }
        sl=0;
        int t;
        for(int i=0,t2=1;i<=3;++i,t2*=2)
            for(int j=0,t3=1;j<=2;++j,t3*=3)
                for(int k=0,t5=1;k<=1;++k,t5*=5)
                     for(int l=0,t7=1;l<=1;++l,t7*=7)
                     {
                         t=t2*t3*t5*t7;
                        li[t]=++sl;
                        il[sl]=t;
                    }
    }
     
    int main()
    {
        memset(dp,-1,sizeof(dp));
        int T;
        LL l,r;
        pre();
        scanf("%d",&T);
        while(T--)
        {
            cin>>l>>r;
            cout<<solve(r)-solve(l-1)<<'
';
        }
    }
原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/14031348.html