• CodeForces 55D 数位统计


    a positive integer number is beautiful if and only if it is divisible by each of its nonzero digits.
    问一个区间内[l,r]有多少个Beautiful数字
    范围9*10^18

    一个数字要被它的所有非零位整除,即被他们的LCM整除,可以存已有数字的Mask,但更好的方法是存它们的LCM{git[i]}

    int MOD = LCM{1,2,9} = 5 * 7 * 8 * 9 = 2520

    10以内的数字情况为2^3 , 3^2 , 5 , 7

    所以最小公倍数组合的情况只有4*3*2*2 = 48

    所以复杂度大概为19*2520*48*10(状态数*决策数)

    View Code
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <string>
    using namespace std;
    
    #define LL __int64
    const int Mod = 2520;
    LL dp[19][2520][48];
    int git[2522];
    int num[19];
    
    int gcd(int a,int b) {
        int mod;
        while(b) {
            mod = a % b;
            a = b;
            b = mod;
        }
        return a;
    }
    
    int Lcm(int a,int b) {
        return a * b / gcd(a,b);
    }
    
    void init() {
        int num = 0;
        for(int i = 1; i <= Mod; i++) {
            if(Mod % i == 0)
                git[i] = num++;
        }
        memset(dp,-1,sizeof(dp));
    }
    
    LL dfs(int dep,int Sum,int preLcm,bool doing) { //doing记录是否满,即是否可以从0到9枚举
        if(dep == -1) 
            return Sum % preLcm == 0;
        if(!doing && dp[dep][Sum][git[preLcm]] != -1) //doing为满的时候可以存起来当成公共的状态使用,降低复杂度    
            return dp[dep][Sum][git[preLcm]];
        int end = doing? num[dep]:9;
        LL ans = 0;
        for(int i = 0; i <= end; i++) {
            int nowSum = (Sum * 10 + i) % Mod;
            int nowLcm = preLcm;
            if(i)
                nowLcm = Lcm(nowLcm,i);
            ans += dfs(dep - 1, nowSum, nowLcm, doing && end == i);
        }
        if(!doing)//记录一般情况,不要记录特殊情况
            dp[dep][Sum][git[preLcm]] = ans;
        return ans;
    }
    
    LL cal(LL x) {
        int i = 0;
        while(x) {
            num[i++] = x % 10;
            x /= 10;
        }
        return dfs(i-1,0,1,1);
    }
    
    int main() {
        int T;
        scanf("%d",&T);
        init();
        while(T--) {
            LL l, r;
            cin >> l >> r;
            cout << cal(r) - cal(l-1) << endl;
        }
        return 0;
    }
  • 相关阅读:
    artTemplate的使用总结
    死锁的简单实现
    代理模式
    装饰器模式
    建造者模式
    工厂模式
    单例模式
    linux查看日志内容
    系统信息及系统操作
    设计模式-建造者模式
  • 原文地址:https://www.cnblogs.com/gray035/p/3008862.html
Copyright © 2020-2023  润新知