CF-55D-数位DP-Beautiful Number

来源:互联网 发布:网络提现 需要牌照 编辑:程序博客网 时间:2024/05/21 04:16

题意
求给定区间内 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 2520typedef 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 ;}
0 0
原创粉丝点击