CodeForces - 55D(数位dp,离散化)

题目来源:http://codeforces.com/problemset/problem/55/D

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).

Input
1
1 9
Output
9
Input
1
12 15
Output
2

 Beautiful numbers定义:能被自身所有非零数位整除的数。就比如15是Beautiful numbers,因为15可以被1,5整除,14不是,因为14不能被4整除。

问:n到m区间内有多少个Beautiful numbers

解题思路:一眼看很容易想到这是一道数位dp的题,我们可以想到:如果这个数是 Beautiful numbers,那么它一定可以被他的所有非零数位的最小公倍数整除。

1-9的最小公倍数是2520

我们可以定义某个状态dp[i][j][k]为第i号数位,j为当前表示的数字,k为当前数位的最小公倍数

如果直接这样写的话,j的范围就是1 ~ 9 ·1018,这肯定是不行的,这里有一个取模的规律:a%(b*c)%c=a%c

所以我们就可以把j的范围缩小到1-2520(1到9的最小公倍数)了。

然而这样还是不行,因为无法开出20*2520*2520的数组,我们可以知道1-9的组合的最小公倍数一定可以被2520整除的,所以先把先对1-2520进行离散化,离散化后可以发现其实只有48个有用的而已,呢么就可以开20*2520*50的数组来

存状态了。

这里插上本人的AC代码。。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<stack>
#include<cstdio>
#include<map>
#include<set>
#include<string>
#include<queue>
using namespace std;
#define inf 0x3f3f3f3f
typedef long long ll;
const int maxn=2520+30;
ll dp[25][maxn][50];
int a[25],hash1[maxn];
inline ll gcd(ll i,ll j){
    return j==0?i:gcd(j,i%j);
}
inline ll lcm(ll i,ll j){
    return i/gcd(i,j)*j;
}
ll dfs(ll pos,ll sum,ll sum1,bool limit){
    if(pos==-1){
        return sum%sum1==0;
    }
    if(!limit&&dp[pos][sum][hash1[sum1]]!=-1){
    //    cout<<pos<<endl;
    //    cout<<dp[pos][sum][hash1[sum1]]<<endl;
        return dp[pos][sum][hash1[sum1]];
    }
    ll up=limit?a[pos]:9;
    ll ans=0;
    for(int i=0;i<=up;i++){
        ans+=dfs(pos-1,(sum*10+i)%2520,i==0?sum1:lcm(sum1,i),(i==up)&&limit);
    }
    if(!limit)
    dp[pos][sum][hash1[sum1]]=ans;
    return ans;
}
ll solve(ll s){
    memset(a,0,sizeof(a));
    int len=0;
    while(s){
        a[len++]=s%10;
        s/=10;
    }
    return dfs(len-1,0,1,true);
}
int main(){
    int t;
    int cnt=0;
    ll l,r;
    scanf("%d",&t);
     for(int i=1;i<=2520;i++)
    {
        if(2520%i==0)
        hash1[i]=cnt++; 
    }
    memset(dp,-1,sizeof(dp));
    while(t--){
            cin>>l>>r;
    //cout<<solve(l-1)<<" "<<solve(r)<<endl;
         cout<<solve(r)-solve(l-1)<<endl;
         //cin>>l;
        // cout<<solve(l)<<endl;
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Zhi-71/p/10060006.html