CF-55D-数位DP-Beautiful Number

题意
求给定区间内 beautiful number 的数目
beautiful number :能被它自身非零位整除
思路
一个数字要被它的所有非零位整除,即被他们的LCM整除
若 x 为beautiful number
则有 x %LCM{DIGIT[xi]} == 0
⇒ x%MOD%LCM{DIGIT[xi]} == 0 其中 MOD为LCM{1…9}
我们可以记录DP[数位][num%MOD][num的LCM]
当且 num%MOD %num的LCM == 0 时 表示找到一个beautiful number
且 nextnum = num*10 +nextdigit
nextLCM = nextdigit ?LCM{num的LCM,nextdigit}:num的LCM
//nextdigit要不为零
这时我们可以拿三维数组存储结果 dp[20][2050][2050]
但是这样三维数组过大 无法运行
要将Num的LCM离散化
10以内最小公倍数组合 共有48种情况
故dp[20][2050][48]
这时就能存下了
接下来DFS解决

/************************************************************************* > File Name: main.cpp > Author:Chazz > Created Time: 2015年11月04日 星期三 23时09分48秒 ************************************************************************/

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <string.h>
#include <algorithm>
#include <vector>
#define MOD 2520
typedef long long ll;
using namespace std;
ll dp[21][MOD+5][55];
int inde[MOD+5];
int bit[20];
void init(){//初始化 且对NUM的LCM 离散化 
    int cnt = 0;
    memset(dp,-1,sizeof(dp));
    for(int i = 1;i <= MOD;i++){
        if(MOD%i==0){
            inde[i] = cnt++;
        }
    }
}
ll gcd(ll a,ll b){
    return b==0?a:gcd(b,a%b);
}
ll lcm(ll a,ll b){
    return a/gcd(a,b)*b;
}
ll dfs(int pos ,int presum,int prelcm,bool flag){
    if(pos < 1){ //数位判断返回
        return ( presum%prelcm == 0);
    }

    if(!flag && dp[pos][presum][inde[prelcm]]!=-1){
        return dp[pos][presum][inde[prelcm]];
    }
    int end = flag?bit[pos]:9;
    ll ans = 0;
    for(int i = 0;i <= end;i++){
        ans += dfs(pos-1,(presum*10+i)%MOD,i==0?prelcm:lcm(prelcm,i),flag&&i==end);
    }
    if(!flag){
        dp[pos][presum][inde[prelcm]] = ans;
    }
    return ans;

}
ll solve(ll n){
    int len = 0;
    while(n){
        bit[++len] = n%10;
        n = n/10;
    }
    return dfs(len ,0,1,1);
}
int main(void){
    int t;
    init();
    ll a,b;
    cin>>t;
    while(t--){
        cin>>a>>b;
        cout<<solve(b)-solve(a-1)<<endl;
    }
    return 0 ;

}

你可能感兴趣的:(ACM)