zoukankan      html  css  js  c++  java
  • Codeforces Beta Round #51 D. Beautiful numbers(数位dp)

    题目链接:https://codeforces.com/contest/55/problem/D

    题目大意:给你一段区间[l,r],要求这段区间中可以整除自己每一位(除0意外)上的数字的整数个数,例如15,因为15既可以整除1也可以整除5,所以15符合要求。
    (1 ≤ li ≤ ri ≤ 9 ·1018).
    Examples
    input
    Copy
    1
    1 9
    output
    Copy
    9
    input
    Copy
    1
    12 15
    output
    Copy
    2


    解题思路:很明显的数位dp,首先我们可以想一个数要整除它的每一位除0意外,那我们可以转化成可以整除它的每一位的最小公倍数即可。而我们可以直接求出1-9的最小公倍数为2520,取模不改变它们间的倍数关系,因为数很大所以我们每次可以对2520取模就可以了。所以我们可以很容易想到定义一个数组dp[20][2525][2525],dp[pos][mul][sta]表示的是第搜索到第pos位数值为mul(模2520后)每一位的最小公倍数为sta的合法数的个数,但我们发现这样状态数很多是会超时的,所以我们必须想办法进行优化,我们认真想想发现比2520小的数中并不是每一个数都有可能是1-9中某些数字的倍数,我们把2520中可能是1-9某些数字的倍数的数筛出来就好了,发现只有48个,我们把dp数组改为dp【20】【2525】【50】,这样就不会超时了,相当于做了一个离散化处理。
    #include<bits/stdc++.h>
    using namespace std;
    typedef unsigned long long ll;
    int gcd(int a,int b){return b?gcd(b,a%b):a;}
    int lcm(int a,int b){return a/gcd(a,b)*b;}
    int a[20],k[2555];
    ll l,r,dp[20][2525][50];
    ll dfs(int pos,int mul,int sta,int limit){
        if(pos==0) return mul%sta==0;
        if(!limit&&dp[pos][mul][k[sta]]!=-1)
        return dp[pos][mul][k[sta]];
        int up=limit?a[pos]:9;
        ll ans=0;
        for(int i=0;i<=up;i++){
            if(i==0){ //当该位为0时,不求最小公倍数 
                ans+=dfs(pos-1,mul*10%2520,sta,limit&&i==a[pos]);
            }else{
                int tmp=lcm(sta,i);
                ans+=dfs(pos-1,(mul*10+i)%2520,tmp,limit&&i==a[pos]);
            }
        }
        if(!limit&&dp[pos][mul][k[sta]]==-1)
        dp[pos][mul][k[sta]]=ans;
        return ans;
    }
    ll solve(ll x){
        int pos=0;
        while(x){
            a[++pos]=x%10;
            x/=10;
        }
        return dfs(pos,0,1,1);
    }
    int main(){
        memset(dp,-1,sizeof(dp));
        int t,cnt=0;
        cin>>t;
        for(int i=1;i<=2520;i++){
            if(2520%i==0)k[i]=++cnt; //2520%i不为0表示i一定不是1-9中某些数字的最小公倍数 
        }
        while(t--){
            cin>>l>>r;
            cout<<solve(r)-solve(l-1)<<endl;
        }
        return 0;
    } 
  • 相关阅读:
    数组
    数据结构的三个方面
    java数据结构和算法
    HashMap实现原理
    面试必问---HashMap原理分析
    Java中:>>>和>>区别
    java运算符 与(&)、非(~)、或(|)、异或(^)
    Java集合详解(全)
    String、StringBuffer、StringBuilder的区别
    abstract关键字、final关键字、static关键字、访问修饰符详解
  • 原文地址:https://www.cnblogs.com/zjl192628928/p/10630611.html
Copyright © 2011-2022 走看看