Files
python/TangDou/AcWing/DP/ShuWei/BZOJ1799.cpp
HuangHai 1f397eca87 'commit'
2025-08-30 18:35:01 +08:00

59 lines
2.1 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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有效
第二维:已经走完的路径,每位的数位和
第三维:已经走完的路径,每位的拼接值(十进制)
前提:已经走到pos这个位置,前面积累下来的数位和是sum,前面的数字拼接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;
}