You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

59 lines
2.1 KiB

2 years ago
#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>
using namespace std;
typedef long long ll;
const int N = 170;
int a[20], mod;
/*
f[pos][sum][pre]
18~1
()
possum,pre(10), ()
*/
ll f[20][N][N];
//此处注意一下pre如果是类型ll,则会第9个点TLE是类型int,则可以AC!
ll dfs(int pos, int sum, int pre, bool limit) {
// 如果走完了全程pre=原数%mod,如果最后pre还能整除mod,并且sum等于mod,则贡献数字1个
if (pos == 0) return pre == 0 && sum == mod;
if (!limit && ~f[pos][sum][pre]) return f[pos][sum][pre];
ll ans = 0;
int up = limit ? a[pos] : 9;
for (int i = 0; i <= up; i++) {
// sum+i:数位和+i
// (pre * 10 + i) % mod : 不断的拼接前缀数字(十进制)但不能盲目记录原始数字需要分组按什么分组呢当然是按枚举的当前mod分组
// 上面这句是本题的精华!
ans += dfs(pos - 1, sum + i, (pre * 10 + i) % mod, limit && i == a[pos]);
}
//记忆化结果
if (!limit) f[pos][sum][pre] = ans;
return ans;
}
ll calc(ll x) {
if (x == -1) return 0; //处理一下边界情况
int al = 0;
while (x) a[++al] = x % 10, x /= 10;
ll res = 0;
for (mod = 1; mod <= 9 * al; mod++) { // max(mod)=9*18=162,数量并不大,可以枚举
memset(f, -1, sizeof f); //每次取的模都会变化,这样状态数组就不再可以重用,需要每次清空
res += dfs(al, 0, 0, true); //其实本题的本质是按分组讨论的方式完成的数量的统计,然后再汇总总数量
}
return res; //返回结果
}
int main() {
ll l, r;
scanf("%lld%lld", &l, &r);
printf("%lld\n", calc(r) - calc(l - 1));
return 0;
}