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
", ++ca, solve(r) - solve(l - 1));
	}
	return 0;
}
原文地址:https://www.cnblogs.com/cxhscst2/p/7502839.html