原题地址:http://acm.hdu.edu.cn/showproblem.php?pid=4389
思路:dp[pos][mod][d][sum]表示前i位数除以d得到余数mod且此时前i位和为sum的数字的个数,这里d在1~81范围内枚举,递归的边界是恰好满足d == sum且mod % sum == 0,最后累加所有的情况即可(枚举d)
很明显,如果直接枚举的话,你每次的模数都会在改变,因此难以下手。所以我们可以换一种思路,先假设定一个固定的模数(范围只有0-81,因此可以枚举),然后最后改成判断是不是合法的就行了。
#include <bits/stdc++.h>
const int INF = 0x7F7F7F7F;
const int MOD = 1e9 + 7;
const double EPS = 1e-10;
const int maxn = 1e5 + 6666;
//这题就是假设了所有的的和的情况,然枚举每一位,判断是不是最后的合法
int dp[12][83][83][83], a[66];
//dp[pos][mod][d][sum]表示前i位数除以d得到余数mod且此时前i位和为sum的数字的个数,
//这里d在1~81范围内枚举,递归的边界是恰好满足d == sum且mod % sum == 0,
//最后累加所有的情况即可(枚举d)
int dfs (int pos, int mod, int d, int sum, bool limit) {
if (pos == 0) return (d == sum && mod % d == 0);
if (!limit && dp[pos][mod][d][sum] != -1) return dp[pos][mod][d][sum];
int res = 0;
int up = limit ? a[pos] : 9;
for (int i = 0; i <= up; i++) {
int tt = (mod * 10 + i) % d;
res += dfs (pos - 1, tt, d, sum + i, limit&&i==up);
}
if(!limit) dp[pos][mod][d][sum] = res;
return res;
}
int solve (int x) {
int cnt = 0;
while (x) {
a[++cnt] = x % 10;
x /= 10;
}
int res = 0;
for (int i = 1; i <= 81; i++)
res += dfs (cnt, 0, i, 0, 1);
return res;
}
int main() {
memset (dp, -1, sizeof (dp));
int t, id = 1;
scanf ("%d", &t);
while (t--) {
int vala, valb;
scanf ("%d%d", &vala, &valb);
printf ("Case %d: %d\n", id++, solve (valb) - solve (vala - 1));
}
return 0;
}