题意:求[A,B]内有多少个数,满足x % f(x) == 0。
解法:数位DP。转化为ans = solve(b) - solve(a - 1)。设dp[i][sum][mod][r]表示长度为i,各位和为sum,模mod余r的数的个数。
当在数字后面新添加一位j时,则有dp[i + 1][sum + j][mod][(r * 10 + j) % mod] += dp[i][sum][mod][r]。
当一个数比n小时,一定是因为从某一位开始出现了当前位的数字比n当前位数字小的情况,从高到低枚举这种情况出现的位数,枚举这位的数字,枚举所有数字的和,即模,满足等式(num + j * 10 ^ i + r) % mod == 0时即符合情况,num为前i位确定时的数值。
for i len...1
for j 0...digit[i]
for mod 1...81
for r 0...mod - 1
if (当前已确定位数值 + j * 10 ^ i + r) % mod == 0
ans += dp[i - 1][mod - 前i位和 - j][mod][r]
代码:
#include<stdio.h> #include<iostream> #include<algorithm> #include<string> #include<string.h> #include<math.h> #include<limits.h> #include<time.h> #include<stdlib.h> #include<map> #include<queue> #include<set> #include<stack> #include<vector> #define LL long long using namespace std; int dp[12][85][85][85] = {0}; int f(int x) { if(x == 0) return 0; return f(x / 10) + x % 10; } void init()//初始化 { for(int i = 0; i < 85; i++) dp[0][0][i][0] = 1; for(int i = 0; i < 9; i++) for(int j = 0; j < 85; j++) for(int k = 0; k < 85; k++) for(int l = 0; l < k; l++) for(int m = 0; m < 10 && m + j < 85; m++) dp[i + 1][j + m][k][(l * 10 + m) % k] += dp[i][j][k][l]; } int solve(int x) { int ans = 0; if(x && (x % f(x) == 0)) ans++; int digit[15] = {0}; int ten[15] = {0, 1, 0}; for(int i = 2; i <= 10; i++) ten[i] = ten[i - 1] * 10; int len = 1; int tmp = x; while(tmp) { digit[len++] = tmp % 10; tmp /= 10; } int sum = 0; int num = 0; for(int i = len - 1; i >= 1; i--)//枚举位数 { for(int j = 0; j < digit[i]; j++) for(int k = 1; k < 85; k++) for(int l = 0; l < k; l++) if((k >= (sum + j)) && ((num + j * ten[i] + l) % k == 0)) ans += dp[i - 1][k - sum - j][k][l]; sum += digit[i]; num += digit[i] * ten[i]; } return ans; } int main() { init(); int T; while(~scanf("%d", &T)) { int cnt = 1; while(T--) { int a, b; scanf("%d%d", &a, &b); printf("Case %d: %d ", cnt++, solve(b) - solve(a - 1)); } } }