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; }

 

你可能感兴趣的:(number)