Beautiful numbers [CF#51 D]

http://www.codeforces.com/problemset/problem/55/D

View Code
//dp[i][j][k] 表示长度为i的,对2520取模为j的,最小公倍数为k的数的个数,1~9最小公倍数只有48个,预处理出来。
const int MM = 11111;
typedef __int64 int64;
#define mod 2520
#define debug puts("wrong")
int64 N,L,R;
int num[MM],cnt;
int64 dp[19][2520][50];
int id[MM], g;

void get_init() {
    g=0;
    for(int i=1;i<=mod;i++) {
        if(mod%i==0) id[i]=g++;
    } 
}
int gcd(int x,int y) {
    int64 tmp;
    while(y) {
        tmp=y;
        y=x%y;
        x=tmp;
    }
    return x;
}

int lcm(int x,int y) { return x/gcd(x,y)*y; }

void get_data() {
    int i,j,k;
    scanf("%I64d%I64d",&L,&R);
}

int64 dfs(int le,int sum,int r,bool less) {
    if(le==-1) return sum%r==0;
    if(!less && dp[le][sum][id[r]]!=-1) return dp[le][sum][id[r]];
    int64 res=0; int d,e=less?num[le]:9,ss,rr;
    for(d=0;d<=e;d++) {
        ss=(sum*10+d)%mod;
        rr=r;
        if(d) rr=lcm(r,d);
        res+=dfs(le-1,ss,rr,less&&d==e);
    }
    if(!less) dp[le][sum][id[r]]=res;
    return res;
}

int64 cal(int64 x) {
    for(cnt=0; x ;num[cnt++]=x%10,x/=10);
    return dfs(cnt-1,0,1,true);
}

void solve() {
    int i,j,k;
    printf("%I64d\n",cal(R)-cal(L-1));
}
int main() {
    get_init();
    memset(dp,-1,sizeof(dp));
    int ca; scanf("%d",&ca);
    while(ca--) get_data(),solve();
    return 0;
}
原文地址:https://www.cnblogs.com/zhang1107/p/3050531.html