HDU4389: X mod f(x) 数位DP
计算区间内一个数字各位之和能整除该数字的个数
d[l][i][j][k]表示前l位和为i模j的结果为k的数的个数,那么就有方程
d[l+1][i+x][j][(k*10+x)%j] += d[l][i][j][k]
预处理出d[l][i][j][k],再逐位统计即可。
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; int bit[10]; int dp[10][82][82][82]; //d[l][i][j][k]表示前l位和为i模j的结果为k的数的个数 void set() { int i,j,k,l,x; for(i = 1; i<=81; i++) dp[0][0][i][0] = 1; for(l = 0; l<9; l++) for(i = 0; i<=l*9; i++) for(j = 1; j<=81; j++) for(k = 0; k<j; k++) for(x = 0; x<=9; x++) dp[l+1][i+x][j][(k*10+x)%j] += dp[l][i][j][k]; } int solve(int n) { if(!n) return 0; int ans,i,j,k,len; int sum,tem1,tem2,s,bit[10],r; len = sum = ans = 0; tem1 = tem2 = n; s = 1; while(tem1) { bit[++len] = tem1%10; tem1/=10; sum+=bit[len];//每位数之和 } if(n%sum==0)//本身要先看是否整除 ans++; for(i = 1; i<=len; i++) { sum-=bit[i];//将该位清0 tem2/=10; s*=10; tem1 = tem2*s; for(j = 0; j<bit[i]; j++) //枚举该位的状况 { for(k = sum+j; k<=sum+j+9*(i-1); k++) //该位与更高位的和,而比该位低的和择优9*(i-1)种 { if(!k)//和为0的状况不符合 continue; r = tem1%k;//现在该数对各位和进行取余 if(r) r = k-r;//余数大于0,那么k-dd得到的数肯定能被t整除 ans+=dp[i-1][k-sum-j][k][r];//加上个数 } tem1+=s/10;//标记现在算到哪里,例如1234,一开始t是1230,然后1231,1232,1233,1234,接下来1200,就是1210,1220,1230 } } return ans; } int main() { int T,l,r,cas = 1; set(); scanf("%d",&T); while(T--) { scanf("%d%d",&l,&r); printf("Case %d: %d\n",cas++,solve(r)-solve(l-1)); } return 0; }