题目要求区间 \([l,r]\) 内各位数字之和与各位数字之积相等的整数个数,不难想到数位 dp。因为没有注意到 \(9\) 个\(0-9\) 整数的乘积状态数只有 \(3000\) 左右,试图用【AHOI2009 同类分布】的做法。原题是求出 \([l.r]\) 中各位数字之和等于原数的个数,做法是枚举原数除以 \(sum\) 的余数 \(m\)(\(9\) 位 \(0-9\) 数字共 \(81\) 种状态),如果最后 \(sum=m, num\equiv 0 \pmod{m}\)。
对于本题,状态转移的 \(num\times 10+i\) 要改成 \(num\times i\)。因为数字可能有前导零,导致乘积为 0,所以需要多开一维 \(0/1\) 判断是否为前导零。如果是则保持 \(num=1\)。
int a[20] = {0}, mod;
int f[20][100][100];int dfs(int len, int lim, int sum, int num, bool zero) {if (len == 0) {if (sum == 0) return 0;return sum == mod && num == 0;}if (!lim && !zero && f[len][sum][num] != -1)return f[len][sum][num];int up = lim ? a[len] : 9;int ans = 0;for (int i = 0; i <= up; ++i) {int t = zero && (!i);ans += dfs(len - 1, lim && i == up, sum + i, (t ? 1 : num * i % mod), t);}if (!lim && !zero) f[len][sum][num] = ans;return ans;
}int calc(int x) {int len = 0;while (x) {a[++len] = x % 10;x /= 10;}int ans = 0;for (mod = 1; mod <= len * 9; ++mod) {memset(f, -1, sizeof f);ans += dfs(len, 1, 0, 1, 1);}return ans;
}