$CF55D [数位DP]$

题面

数位DP+状压。

首先,按照数位DP的基本套路,每个个位数的最小公倍数为2520,所以只用考虑模2520的情况。考虑一个DPdp[i][j][k]表示当前是第i位,2~9的数的集合为j,模2520为k的方案数。然后,就是数位DP的基本套路解决这道题。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
inline LL read () {
    LL res = 0 ;
    int f (1) ;
    char ch = getchar ();
    while (!isdigit(ch)) {
        if (ch == '-') f = -1 ;
        ch = getchar();
    }
    while (isdigit(ch)) res = (res << 1) + (res << 3) + (ch ^ 48),ch = getchar();
    return res * f ;
}
const int N=20;
const int mod=2520;
int p[49]= {0,1,2,3,4,5,6,7,8,9,10,12,14,15,18,20,21,24,28,
            30,35,36,40,42,45,56,60,63,70,72,84,90,105,120,126,140,168,
            180,210,252,280,315,360,420,504,630,840,1260,2520
           };
int _lcm(int m,int n) {
    return (m*n)/__gcd(m, n);
}
LL f[N][49][mod+2], bit[N], has[mod+2];
inline LL dfs(int i,int lcm,int left, bool e) {
    if(i==0) return lcm&&left%p[lcm]==0 ;
    if(!e && ~f[i][lcm][left])    return f[i][lcm][left];
    LL ans=0;
    int u= e? bit[i]: 9;
    for(register int d=0; d<=u; d++) {
        int t= lcm? has[_lcm(p[lcm], max(d,1))]: max(d,0);
        ans+=dfs(i-1, t, (left*10+d)%mod, e&&d==u);
    }
    return e==true? ans: f[i][lcm][left]=ans;
}
LL cal(LL n) {
    int len=0;
    while(n) {
        bit[++len]=n%10;
        n/=10;
    }
    return dfs(len,0,0,true);
}
signed main() {
    ios::sync_with_stdio(false);
    memset(f,-1,sizeof(f));
    for(register int i=0; i<49; i++) has[p[i]]=i;
    LL t=read();
    while( t-- ) {
        LL L=read(),R=read();
        cout<<cal(R)-cal(L-1)<<endl;
    }
    return 0;
}

  

跑的好慢啊QwQ

 

posted @ 2019-03-02 13:23  Isaunoya  阅读(162)  评论(0编辑  收藏  举报
TOP