Beautiful numbers CodeForces - 55D 数位dp

#include<iostream>
#include<cstring>
#include<cstdio> 
using namespace std;
typedef long long ll;
const int MOD=2520;
ll gcd(ll a,ll b) {
    return b==0?a:gcd(b,a%b);
}
ll lcm(ll a,ll b) {
    return a*b/gcd(a,b);
}
ll dp[30][MOD][50];
ll a[30],Hash[MOD];
ll DFS(int pos,int presum,int prelcm,int limit) {
    //到最后以为 
    if(pos==0)
        //当前值 % 出现过的数字的最小公倍数 
        return presum%prelcm==0;
    if(!limit&&dp[pos][presum][Hash[prelcm]]!=-1)
        return dp[pos][presum][Hash[prelcm]];
    int up=limit?a[pos]:9;
    ll res=0;
    for(int i=0; i<=up; i++) {
        int nowsum=(presum*10+i)%MOD;//可以对MOD任意取模而不影响结果
        int nowlcm=prelcm;
        if(i!=0)
            //求出现过的数字的最小公倍数 
            nowlcm=lcm(prelcm,i);
        res+=DFS(pos-1,nowsum,nowlcm,limit&&i==up);
    }
    if(!limit)
        dp[pos][presum][Hash[prelcm]]=res;
    return res;
}
ll solve(ll n) {
    int top=0;
    while(n) {
        a[++top]=n%10;
        n/=10;
    }
    return DFS(top,0,1,1);
}
void Init() {
    int cnt=0;
    for(int i=1; i<=2520; i++) { 
        if(MOD%i==0)
            Hash[i]=cnt++;
    }
}
int main() {
    ios::sync_with_stdio(0);
    Init();
    int T;
    memset(dp,-1,sizeof(dp));
    cin>>T;
    while(T--) {
        ll l,r;
        cin>>l>>r;
        cout<<solve(r)-solve(l-1)<<endl;
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/QingyuYYYYY/p/12500775.html