hdu4389

hdu4389 X mod f(x)
传送门

题意

计算区间\([A,B](1\leq A\leq B\leq 1e9)\)中,能被自己各个数位之和整除的数的个数。

题解

数位\(dp\)
各个数位之和的范围为\([1,81]\),对于每一个和,数位\(dp\)计算满足条件的数的个数。
\(dp[i][x][rest][sum]\)表示从高位到低位直到第\(i\)位数,当前的数模\(x\)的余数是\(rest\),各个数位之和为\(sum\)的数的个数。

#include<bits/stdc++.h>
#define LL long long
#define ULL unsigned long long
#define LD long double
#define PII pair<int,int>
#define PLL pair<LL,LL>
#define PLI pair<LL,int>
#define pi acos(-1.0)
#define eps 1e-6
#define lowbit(x) x&(-x)
using namespace std;

int T,a,b,bit[10],dp[10][82][82][82];

int divide(int x){
    int cnt=0;
    while(x){
        bit[cnt++]=x%10;
        x/=10;
    }
    return cnt;
}

int dfs(int pos,int x,int rest,int sum,bool limit){
    if(pos==-1) return rest==0 && sum==x;
    if(!limit && dp[pos][x][rest][sum]!=-1) return dp[pos][x][rest][sum];
    int up=limit?bit[pos]:9;
    int ans=0;
    for(int i=0;i<=up;i++){
        ans+=dfs(pos-1,x,(rest*10+i)%x,sum+i,limit && i==up);
    }
    if(!limit) dp[pos][x][rest][sum]=ans;
    return ans;
}

int main(){
    memset(dp,-1,sizeof(dp));
    scanf("%d",&T);
    for(int cas=1;cas<=T;cas++){
        scanf("%d %d",&a,&b);
        int cnt1=divide(a-1);
        LL ans1=0;
        for(int i=1;i<=81;i++){
            ans1+=dfs(cnt1-1,i,0,0,1);
        }
        int cnt2=divide(b);
        LL ans2=0;
        for(int i=1;i<=81;i++){
            ans2+=dfs(cnt2-1,i,0,0,1);
        }
        printf("Case %d: %d\n",cas,ans2-ans1);
    }
}
posted @ 2021-03-16 22:44  fxq1304  阅读(22)  评论(0编辑  收藏  举报