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;
}

浙公网安备 33010602011771号