uva11361 - Investigating Div-Sum Property 数位统计DP

来源:互联网 发布:网络说的生煎什么意思 编辑:程序博客网 时间:2024/06/07 14:12

Aninteger is divisible by 3 if the sum of its digits is also divisible by 3. Forexample, 3702 is divisible by 3 and 12(3+7+0+2) is also divisible by 3. Thisproperty also holds for the integer 9.

Inthis problem, we will investigate this property for other integers.

Input

The first line of input is an integer T(T<100) thatindicates the number of test cases. Each case is a line containing 3 positiveintegersA, B and K.1 <= A <=B < 2^31 and0<K<10000.

Output

For each case,output the number of integers in the range [A, B] which is divisible by K and the sumof its digits is also divisible byK.

Sample Input

Output for Sample Input

3

1 20 1

1 20 2

1 1000 4

20

5

64


  区间[A,B]中有多少个数满足:这个数能被K整除并且这个数的所有位之和能被K整除。

  用dp[i][j][k]表示i位的数有多少个每位和被K除余j,这个数被K除余K。比如i=3的时候就是000-999,i=4的时候是0000-9999...

  如果dp求出来了就好做了,区间的话只要求出[0,A-1],[0,B]相减就可以了。对于某个数A,比如3210,每位和被K除余m,这个数被K除余n。那么最高位取0,1,2的时候,后面三位是可以任取的,因此一定有一个dp[3][m'][n']与之对应,当最高位取3的时候,接着递归210,(m-3%K+K)%K,(n-3*10^3%K+K)%K。

  dp也可以用记忆化搜索,也可以递推求,道理是一样的,位数从小到大,相当于每次在最高位多加一位。dp[i][j][k]+=dp[i-1][(j-x%K+K)%K][(k-x*Pow(i-1)%K+K)%K],(0<=x<=9)。

  余数递推的时候要注意小于0的情况。

#include <cstdio>#include <cstring>#include <cmath>#include <queue>#include <stack>#include <vector>#include <string>#include <map>#include <iostream>#include <algorithm>using namespace std;int T,A,B,K,L,dp[12][112][10010];//位数,每位和对K余数,这个数对K余数int bit(int n,int &m){  //m是顺便算出n的最高位    int ret=0;    while(n){        m=n;        ret++;        n/=10;    }    return ret;}int Pow(int n){    int ret=1;    for(int i=0;i<n;i++) ret*=10;    return ret;}void init(){    memset(dp,0,sizeof(dp));    dp[0][0][0]=1;    for(int i=1;i<=L;i++)        for(int j=0;j<K&&j<=i*9;j++)            for(int k=0;k<K;k++)                for(int x=0;x<=9;x++) dp[i][j][k]+=dp[i-1][(j-x%K+K)%K][(k-x*Pow(i-1)%K+K)%K];}int solve(int n,int k1,int k2){ //[0,n) 每位和除K余k1,这个数除K余k2     int m,p=bit(n,m),ret=0;    if(!p) return 0;    for(int i=0;i<m;i++) ret+=dp[p-1][(k1-i%K+K)%K][(k2-i*Pow(p-1)%K+K)%K];    ret+=solve(n%Pow(p-1),(k1-m%K+K)%K,(k2-m*Pow(p-1)%K+K)%K);    return ret;}int main(){    //freopen("in.txt","r",stdin);    scanf("%d",&T);    while(T--){        scanf("%d%d%d",&A,&B,&K);        int ans,t;        L=max(bit(A,t),bit(B,t));        if(K>(bit(B,t))*9) ans=0;        else{            init();            ans=solve(B+1,0,0)-solve(A,0,0);        }        printf("%d\n",ans);    }    return 0;}


0 0