CodeForces 55D Beautiful numbers(数位dp)

14 篇文章 0 订阅
1 篇文章 0 订阅
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 this and just count the quantity of beautiful numbers in given ranges.

Input
The first line of the input contains the number of cases t (1 ≤ t ≤ 10). Each of the next t lines contains two natural numbers li and ri (1 ≤ li ≤ ri ≤ 9 ·1018).

Please, do not use %lld specificator to read or write 64-bit integers in C++. It is preffered to use cin (also you may use %I64d).

Output
Output should contain t numbers — answers to the queries, one number per line — quantities of beautiful numbers in given intervals (from li to ri, inclusively).

Example
Input
1
1 9
Output
9
Input
1
12 15
Output
2
这道题的题意是一个数,如果能够被他所有非0的各位数的数字整除的话,那么他就是一个beautiful numbers.
例如24,既能被2整除,也能被4整数。
然后求范围内的beautiful数有多少个,明显就是数位dp.
一个数能满足beautiful数的条件是什么呢。
其实就是这个数能够被他所有位数上的数字的lcm(最小公倍数)整除。
可是这个数太大怎么办,我们在记录的过程中明显数组的空间就不够大。需要想办法把它压缩。
我们就可以先算出最大的最小公倍数的大小(即1到9的最小公倍数)为2520.
那么我们一个数满足x%lcm(x)=0,(1) 
并且2520%lcm(x)=0,(2)
(1)(2)式子合并得,x%2520%lcm(x)=0;
那么我们就可以把一个beautiful数的范围由9*10^18压缩到2520了。
dp[20][2520][2520](dp[i][j][k])表示长度为i,它的所有位数的lcm为j,且这个数对maxLcm取余为k的数的个数。
这里懂吧,只要满足对应的条件即可。
可是呢,这样子数组的内存占用就太大了,我们需要统计的是满足beautiful数条件的数的个数。
那么第二维我们就可以相对压缩,实际上满足的数(preNum%preLcm=0)也就48个,
所以只需要统计这些满足条件的,不满足条件的直接忽略不需要统计,这样子我们就可以来做题了。//这里需要好好想想为什么。
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<ctime>
#include<string>
#include<stack>
#include<deque>
#include<queue>
#include<list>
#include<set>
#include<map>
#include<cstdio>
#include<limits.h>
#define MOD 1000000007
#define fir first
#define sec second
#define fin freopen("/home/ostreambaba/文档/input.txt", "r", stdin)
#define fout freopen("/home/ostreambaba/文档/output.txt", "w", stdout)
#define mes(x, m) memset(x, m, sizeof(x))
#define Pii pair<int, int>
#define Pll pair<ll, ll>
#define INF 1e9+7
#define inf 0x3f3f3f3f
#define Pi 4.0*atan(1.0)

#define lowbit(x) (x&(-x))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-12;
const int maxn = 36;
using namespace std;

inline int read(){
    int x(0),f(1);
    char ch=getchar();
    while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
const int maxLcm=2520;
ll dp[20][50][maxLcm+10];
int bit[20];
int Hash[maxLcm+10];
inline int gcd(int a,int b)
{
    return b?gcd(b,a%b):a;
}
inline int lcm(int a,int b)
{
    return a/gcd(a,b)*b;
}
ll dfs(int pos,int preNum,bool flag,int preLcm)
{
    if(pos==0){
        return preNum%preLcm==0;
    }
    if(!flag&&~dp[pos][Hash[preLcm]][preNum]){
        return dp[pos][Hash[preLcm]][preNum];
    }
    ll ret=0;
    int x=flag?bit[pos]:9;
    for(int i=0;i<=x;++i){
        int curNum=(preNum*10+i)%maxLcm;
        int curLcm=preLcm;
        if(i){
            curLcm=lcm(preLcm,i);
        }
        ret+=dfs(pos-1,curNum,flag&&i==bit[pos],curLcm);
    }
    if(!flag){
        dp[pos][Hash[preLcm]][preNum]=ret;
    }
    return ret;
}
ll cacl(ll n)
{
    int k=0;
    while(n){
        bit[++k]=n%10;
        n/=10;
    }
    return dfs(k,0,true,1);
}
int main()
{
    int k=0;
    for(int i=1;i<=maxLcm;++i){
        Hash[i]=k+=(maxLcm%i==0);
    }
    mes(dp,-1);
    int t=read();
    ll l,r;
    while(t--){
        scanf("%I64d%I64d",&l,&r);
        printf("%I64d\n",cacl(r)-cacl(l-1));
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值