CF Beautiful numbers (数位dp + 数论)

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

###题意:
求一个区间[l, r]内所有数字能被它每个数字整除的数的个数
###思路:
一个数能被她的每一位数字整除,就是能被他们的最小公倍数整除,而lcm{1,2…9} = 2520,即这个数对2520取模后被最小公倍数整除,即使漂亮数
##AC代码

#include <iostream>
#include <string.h>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <stdio.h>
#include <deque>

using namespace std;

#define LL long long
#define ull unsigned long long
#define INF 0x3f3f3f3f
#define maxn 1005
#define eps 0.00000001
#define PI acos(-1.0)
#define M 1000000007

LL dp[30][2550][50];
int num[30];
map<int, int> MM;

int gcd(int a, int b) {
    return b == 0 ? a : gcd(b, a % b);
}

int lcm(int a, int b) {
    return a/gcd(a, b) * b;
}

LL dfs(int pos, int m, int status, bool limit) {
    if(!pos) return m % status == 0;
    if(!limit && dp[pos][m][MM[status]]) return dp[pos][m][MM[status]];
    int end = limit ? num[pos] : 9;
    LL sum = 0; int a;
    for (int i = 0; i <= end; i ++) {
        if(!i) a = status;
        else a = lcm(status, i);
        sum += dfs(pos - 1, (m * 10 + i) % 2520, a, limit && (i == end));
    }
    return limit ? sum : dp[pos][m][MM[status]] = sum;
}

LL solve(LL n) {
    num[0] = 0;
    while(n) {
        num[++ num[0]] = n % 10;
        n /= 10;
    }
    return dfs(num[0], 0, 1, 1);
}

void init() {
    memset(dp, 0, sizeof(dp));
    MM[1] = 1;    MM[2] = 2;    MM[3] = 3;    MM[4] = 4;
    MM[5] = 5;    MM[6] = 6;    MM[7] = 7;
    MM[8] = 8;    MM[9] = 9;
    MM[10] = 10;    MM[12] = 11;
    MM[14] = 12;    MM[15] = 13;
    MM[18] = 14;    MM[20] = 15;
    MM[21] = 16;    MM[24] = 17;
    MM[28] = 18;    MM[30] = 19;
    MM[35] = 20;    MM[36] = 21;
    MM[40] = 22;    MM[42] = 23;
    MM[45] = 24;    MM[56] = 25;
    MM[60] = 26;    MM[63] = 27;
    MM[70] = 28;    MM[72] = 29;
    MM[84] = 30;    MM[90] = 31;      MM[105] = 32;    MM[120] = 33;    MM[126] = 34;
    MM[140] = 35;    MM[168] = 36;    MM[180] = 37;
    MM[210] = 38;    MM[252] = 39;    MM[280] = 40;
    MM[315] = 41;    MM[360] = 42;    MM[420] = 43;    MM[504] = 44;
    MM[630] = 45;    MM[840] = 46;    MM[1260] = 47;
    MM[2520] = 48;
}

int main(int argc, const char * argv[]) {
    LL T, l, r;
    init();
    scanf("%I64d", &T);
    while(T --) {
        scanf("%I64d %I64d", &l, &r);
        printf("%I64d\n", solve(r) - solve(l - 1));
    }
    return 0;
}
}

猜你喜欢

转载自blog.csdn.net/henu_jizhideqingwa/article/details/82692189