CodeForces 55D Beautiful numbers 数位DP+数学

题意大概是,判断一个正整数区间内有多少个整数能被它自身的每一个非零的数字整除。

因为每一个位置上的整数集s = {0,1,2,3,4,5,6,7,8,9} lcm(s) = 2520

现在有一个整数t是由s中一个或者多个数字构成的,记为abcde,显然t = a*10^4+b*10^3+c*10^2+d*10^1+e

要使得t能被a,b,c,d,e整除,必然有t % lcm(a,b,c,d,e) = 0 因为a,b,c,d,e去重之后一定是s的一个子集,所以lcm(s)一定是lcm(a,b,c,d,e)的倍数,所以只要

t % lcm(s) % lcm(a,b,c,d,e) = 0 满足答案。

一开始不知道这道题应该怎么存储状态,因为随着数字的变化,这个lcm(a,b,c,d,e)是会改变的,没法直接存储对lcm(a,b,c,d,e)的余数,但是lcm(s)是不变的,所以我们只要存储lcm(s)的余数和lcm(a,b,c,d,e)就好了,因为一共就九个数字,lcm一共只有48个,所以复杂度为lcm(s)*48*maxlen

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <climits>
#include <string>
#include <iostream>
#include <map>
#include <cstdlib>
#include <list>
#include <set>
#include <queue>
#include <stack>

using namespace std;

typedef long long LL;
const int maxn = 20;
const int mod = 2520;
int lim[maxn],len;
LL f[maxn][50][mod];
map<int,int> st;
int ccon[(1 << 10)],clcm[50];

void getlim(LL num) {
    len = 0;
    memset(lim,0,sizeof(lim));
    while(num) {
        lim[len++] = num % 10;
        num /= 10;
    }
}

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

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

void init() {
    int cnt = 0;
    for(int i = 1;i < (1 << 10);i++) {
        int nlcm = 1;
        for(int j = 1;j <= 9;j++) if(i & (1 << j)) {
            nlcm = lcm(nlcm,j);
        }
        if(!st.count(nlcm)) {
            st[nlcm] = cnt;
            clcm[cnt++] = nlcm;
        }
        ccon[i] = st[nlcm];
    }
    ccon[0] = -1;
}

LL dfs(int now,int mask,int rest,int bound) {
    if(now == 0) {
        if(mask <= 1) return 0;
        return rest % clcm[ccon[mask]] == 0;
    }
    LL &note = f[now][ccon[mask]][rest];
    if(!bound && note != -1 && mask > 1) return note;
    int m = bound ? lim[now - 1] : 9;
    LL ret = 0;
    for(int i = 0;i <= m;i++) {
        ret += dfs(now - 1,mask | (1 << i),(rest * 10 + i) % mod,i == m && bound);
    }
    if(!bound && mask > 1) note = ret;
    return ret;
}

LL solve(LL num) {
    getlim(num);
    return dfs(len,0,0,1);
}

int main() {
    memset(f,-1,sizeof(f));
    init();
    int T; cin >> T;
    while(T--) {
        LL a,b; cin >> a >> b;
        cout << solve(b) - solve(a - 1) << endl;
    }
    return 0;
}

  

CodeForces 55D Beautiful numbers 数位DP+数学

时间: 2024-10-11 06:29:46

CodeForces 55D Beautiful numbers 数位DP+数学的相关文章

CodeForces 55D Beautiful numbers(数位dp&amp;&amp;离散化)

题目链接:[kuangbin带你飞]专题十五 数位DP A - Beautiful numbers 题意 ps:第一道数位dp,题真好,虽然是参考大牛方法悟过才a,但仍收获不少. 求一个区间内的Beautiful numbers有多少个.Beautiful numbers指:一个数能整除所有组成它的非0数字. 例如15可以被1和5整除,所以15是Beautiful numbers. 思路 Beautiful numbers指:一个数能整除所有组成它的非0数字. 等同于 一个数能整除 所有组成它的

CodeForces 55D - Beautiful numbers - [数位DP+离散化]

题目链接:https://cn.vjudge.net/problem/CodeForces-55D Volodya is an odd boy and his taste is strange as well. It seems to him that a positive integer number is beautiful if and only if it is divisible by each of its nonzero digits. We will not argue with

CodeForces - 55D - Beautiful numbers(数位DP,离散化)

链接: https://vjudge.net/problem/CodeForces-55D 题意: Volodya is an odd boy and his taste is strange as well. It seems to him that a positive integer number is beautiful if and only if it is divisible by each of its nonzero digits. We will not argue with

CodeForces 55D Beautiful numbers (数位DP)

题意:给求给定区间中该数能整除每一位的数的数量. 析:dp[i][j][k] 表示前 i 位,取模2520为 j,最小倍数是 k,但是这样,数组开不下啊,那怎么办呢,其实,0-9的最小公倍数的不同各类并没有那么多, 其实就48种,所以我们可以给这48个一个编号,然后就能开出来了. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <strin

Codeforces 55D Beautiful numbers 数位dp(入门

题目链接:点击打开链接 题意: 我们认为一个数 num 能被每一位上的数字整除(expect 0) 那么这个数num就是合法的. 给出区间[l,r] ,问这个区间内有多少个合法的数. 首先solve(long x) 返回 [0, x] 内的合法个数,答案就是 solve(r) - solve(l-1); 以1234567为例 flag表示当前这位是能任意填,还是只能填<=该位对应的数字 若当前搜索的是第三位,且第二位已经填了0或1,则此时第三位可以任意填. 若第二位填的是2,则第三位只能填 [0

FZU2179/Codeforces 55D beautiful number 数位DP

题目大意: 求  1(m)到n直接有多少个数字x满足 x可以整出这个数字的每一位上的数字 思路: 整除每一位.只需要整除每一位的lcm即可 但是数字太大,dp状态怎么表示呢 发现 1~9的LCM 是2520 ....也就是说只要对这个数mod2520 剩下的余数能整除lcm就可以整除了.. 计数的时候还有一个技巧,具体见注释 此外这个题还卡常数了,预处理lcm才过了.. 代码如下: #include <iostream> #include <stdio.h> #include<

Codeforces 55D. Beautiful numbers(数位DP,离散化)

Codeforces 55D. Beautiful numbers 题意 求[L,R]区间内有多少个数满足:该数能被其每一位数字都整除(如12,24,15等). 思路 一开始以为是数位DP的水题,觉得只需要记录搜到当前位出现了哪些数字作为状态即可,明显是假算法...感觉这是一道数位DP好题.可以这样思考:一个数要想被其各位数字分别都整除,等价于它被那些数字的LCM整除.因此记录当前位,当前数对(1~9的LCM)取模的结果,当前出现的数字的LCM这三个值作为状态才合理,即dp[pos][sum][

CodeForces 55D Beautiful numbers(数位dp+数学)

题目链接:http://codeforces.com/problemset/problem/55/D 题意:一个美丽数就是可以被它的每一位的数字整除的数. 给定一个区间,求美丽数的个数. 显然这是一道数位dp,就是满足一个数能被所有位数的lcm整除即可. 一般都会设dp[len][mod][LCM],mod表示余数,LCM表示前len位的lcm. 但是如果直接裸mod会很复杂,于是再想lcm{0,1,2,3,4,5,6,7,8,9}=2520; 而且lcm{a,b,c,d....}{a,b,c,

codeforces 55D D. Beautiful numbers(数位dp+数论)

题目链接: codeforces 55D 题目大意: 求在[l,r]中能够整除自己每个数位上的数字的数的个数. 题目分析: 首先我们能够知道如果这个数能够整除它的每个数位上的数字,那么它一定能够整除他们的最小公倍数,是充要的. 那么我们定义状态dp[i][j][k]代表i位在任意组合下得到的所有数位的数字的最小公倍数为j的每个数位上的数字之积%2520为k的方案数. 我们可以知道所有的公倍数最大不会超过2520,而且他们都是2520的约数,所以如果他们能够整除2520的余数,那么证明他们能够整除