zoukankan      html  css  js  c++  java
  • 51nod 1232 完美数 | 数位DP

    51nod 1232 完美数

    题面

    如果一个十进制数的每一位都是它的因数,则称这个数为完美数。
    给出L, R(L, R <= 1e18),求出[L, R]中完美数的个数。

    题解

    做这道题,我才了解数位DP的套路写法……下次做数位DP应该就不会绞尽脑汁处理写法上的问题了。

    dp[i][j][k]表示长度为i,模2560(1~9的LCM)得j,所有位上的数的LCM为k的数的个数。
    它包括了所有的长度为i的数,例如i=5时,它要考虑的是10000~99999之间所有的数。

    这里的k理论上也是一个小于等于2560的数,但这样太大了,需要离散化一下。打表发现1~9不同组合的LCM只有48个,很适合离散化。

    数位DP的套路:用一个记忆化的dfs解决问题。详见代码。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    #define INF 0x3f3f3f3f
    #define space putchar(' ')
    #define enter putchar('
    ')
    using namespace std;
    typedef long long ll;
    template <class T>
    bool read(T &x){
        char c;
        bool op = 0;
        while(c = getchar(), c < '0' || c > '9')
    	if(c == '-') op = 1;
    	else if(c == EOF) return 0;
        x = c - '0';
        while(c = getchar(), c >= '0' && c <= '9')
    	x = x * 10 + c - '0';
        if(op) x = -x;
        return 1;
    }
    template <class T>
    void write(T x){
        if(x < 0) putchar('-'), x = -x;
        if(x >= 10) write(x / 10);
        putchar('0' + x % 10);
    }
    const int N = 2530, M = 50;
    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 f[N], g[]={0,1,2,3,4,5,6,7,8,9,10,12,14,15,18,20,21,24,28,30,35,36,40,42,45,56,60,63,70,72,84,90,105,120,126,140,168,180,210,252,280,315,360,420,504,630,840,1260,2520};
    ll T, L, R, num[20];
    ll dp[20][N][M];
    void init(){
        for(int i = 1; i <= 48; i++)
    	f[g[i]] = i;
        memset(dp, -1, sizeof(dp));
    }
    ll dfs(int i, int j, int k, bool flag){
        if(!i) return j % g[k] == 0;
        if(!flag && dp[i][j][k] != -1) return dp[i][j][k];
        ll res = 0, lim = flag ? num[i] : 9;
        for(int x = 0; x <= lim; x++){
    	int newk = x ? f[lcm(g[k], x)] : k;
    	res += dfs(i - 1, (j * 10 + x) % 2520, newk, flag && x == lim);
        }
        return flag ? res : dp[i][j][k] = res;
    }
    ll solve(ll x){
        int len = 0;
        while(x) num[++len] = x % 10, x /= 10;
        return dfs(len, 0, 1, 1);
    }
    int main(){
        init();
        read(T);
        while(T--){
    	read(L), read(R);
    	write(solve(R) - solve(L - 1)), enter;
        }
        return 0;
    }
    
  • 相关阅读:
    闭包(closure)与协程共用时要注意的事情
    mysql---视图
    职责链模式
    JavaScript DOM(一)
    9.7 迭代
    [BLE--Link Layer]设备蓝牙地址
    Loopback測试软件AX1用户手冊 V3.1
    操作系统
    OpenCV特征点检測------Surf(特征点篇)
    linux 命令 xxd
  • 原文地址:https://www.cnblogs.com/RabbitHu/p/51nod1232.html
Copyright © 2011-2022 走看看