1. 程式人生 > >【數位DP】 【CodeForces 55D】

【數位DP】 【CodeForces 55D】

題意:求區間[a, b]中有多少個數能整除自身的每個非0數位。

分析:一個數位只有1~9種可能,而1~9的lcm=2520。滿足要求的數所有數位的lcm一定是2520的因子,

      所以可先求出2520的所有因子,一開始都對2520取mod,這樣對結果沒有任何影響,最後再對所有數

      位的lcm取mod,如果為0則滿足。

程式碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>

using namespace std;
typedef long long LL;
const int maxn=2520;
int digit[20], a[50], t=0;
LL dp[20][maxn][50];
map<int,int>m;

int GCD(int a, int b) {
    return b==0?a:GCD(b, a%b);
}
int LCM(int a, int b) {
    return a/GCD(a,b)*b;
}
LL dfs(int pos, int mod, int lcm, bool limit) {
    if(!pos) return (mod%a[lcm]==0);
    if(!limit&&dp[pos][mod][lcm]!=-1) return dp[pos][mod][lcm];
    int len=(limit?digit[pos]:9);
    LL ret=0LL;
    for(int i=0; i<=len; ++i)
        ret+=dfs(pos-1, (mod*10+i)%maxn, i==0?lcm:m[LCM(a[lcm],i)], limit&&i==len);
    if(!limit) dp[pos][mod][lcm]=ret;
    return ret;
}
LL work(LL x) {
    int len=0;
    while(x) digit[++len]=x%10, x/=10;
    return dfs(len, 0, 0, true);
}
int main() {
    memset(dp, -1, sizeof(dp));
    for(int i=1; i<=maxn; ++i)
        if(maxn%i==0) a[t]=i, m[i]=t++;
    int T; cin>>T;
    while(T--) {
        LL a, b; cin>>a>>b;
        cout<<work(b)-work(a-1)<<endl;
    }
    return 0;
}