HDU 4389 X mod f(x) (数位DP)
题目链接 HDU4389
题意 给出T个区间[L, R],统计L到R中有多少个满足条件的数。
限制条件为该数能被这个数的各位数字之和整除。
数据范围$1 <= L <= R <= 10^{9}$
考虑数位DP
注意到f(x)最大为81,所以对1-81每一个和做一遍数位DP即可。
f[pos][mod][sum][x] 表示当前处理到第pos位,当前的数位和对x取模的结果,当前的数位和,以及当前正在求的x = f(x)
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) int f[11][82][82][82]; int a[12]; int T; int l, r; int ca = 0; int dp(int pos, int mod, int sum, int x, int flag){ if (pos == 0) return x == sum && mod == 0; if (!flag && ~f[pos][mod][sum][x]) return f[pos][mod][sum][x]; int ret = 0; int ed = flag ? a[pos] : 9; rep(i, 0, ed) ret += dp(pos - 1, (mod * 10 + i) % x, sum + i, x, flag && i == a[pos]); if (!flag) f[pos][mod][sum][x] = ret; return ret; } int solve(int x){ int len = 0, ret = 0; for (; x; x /= 10) a[++len] = x % 10; rep(i, 1, 81) ret += dp(len, 0, 0, i, 1); return ret; } int main(){ memset(f, -1, sizeof f); scanf("%d", &T); while(T--){ scanf("%d%d", &l, &r); printf("Case %d: %d\n", ++ca, solve(r) - solve(l - 1)); } return 0; }