CF 55D - Beautiful numbers(数位DP)

题意:

如果一个数能被自己各个位的数字整除,那么它就叫 Beautiful numbers。
求区间 [a,b] 中 Beautiful numbers 的个数。

分析:先分析出,2~9 的最大的最小公倍数是 2520({5,7,8,9}),先预处理出所有可能的最小公倍数m[c]

dp[i][d][c]表示长度i, 余数d,各位上的数的最小公倍数是m[c]的个数。

#include<cstdio>
#include<cstring>
#define mod 2520
ll dp[35][2520][100];
int bit[64],m[200],mnum;
int gcd(int a,int b){
    int tmp;
    while(a%b){
        tmp=b;
        b=a%b;
        a=tmp;
    }
    return b;
}
int lcm(int a,int b){
    return a*b/gcd(a,b);
}
//查最小公倍数的标号
int tfind(int x){ int ll=1,rr=mnum; while(ll<=rr){ int mid=(ll+rr)>>1; if(m[mid]<x)ll=mid+1; else rr=mid-1; } return ll; } void init(){ memset(dp,-1,sizeof(dp)); mnum=0; for(int i=1;i<=mod;++i) if(mod%i==0) m[++mnum]=i; } ll dfs(int i,int d,int c,int e){ if(i==0)return d%m[c]?0:1; if(!e&&dp[i][d][c]!=-1)return dp[i][d][c]; int l=e?bit[i]:9; ll num=0; for(int j=0;j<=l;++j) { int td=(d*10+j)%mod; int tc=c; if(j)tc=tfind(lcm(m[c],j)); num+=dfs(i-1,td,tc,e&&(j==l)); } return e?num:dp[i][d][c]=num; } ll solve(ll x){ int len=0; while(x){ bit[++len]=x%10; x/=10; } return dfs(len,0,1,1); } int main() { int t; scanf("%d",&t); init(); ll x,y; while(t--){ scanf("%I64d%I64d",&x,&y); printf("%I64d\n",solve(y)-solve(x-1)); } return 0; }

 

posted on 2015-07-25 10:49  积跬步、至千里  阅读(180)  评论(0编辑  收藏  举报

导航