超级难想的一道题
用一棵十叉数来统计
因为是各个数位之和 所以要把之前各个数位的和sum记录下来
因为每个数位(子树)并不一定完整的分成cnt组 最后可能有剩余 所以每一个数位(子树)前面肯能会有多余的空间 用rem记录
因为需要每组末的空间是在统计时不断改变的 所以dp时要同时记录组数和最后的空余
实现方面 沿用上一个记忆化搜索的思路 传入两个参数unlimit1 unlimit2 表示该位置上的数的取值是否受到读入的L 和 R 的限制 只有不受限制时找到的DP值才能作为d数组中的元素记录下来
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
const int MAXN = 18;
const int MAXK = 1000;
struct node{
LL cnt, res;
node(){}
node(LL x, LL y) { cnt = x; res = y; }
node operator += (node t)
{
cnt += t.cnt;
res = t.res;
return *this;
}
}d[MAXN+10][MAXN * 9 + 10][MAXK+10];
bool vis[MAXN+10][MAXN * 9 + 10][MAXK+10];
int digL[MAXN+10], digR[MAXN+10];
LL L, R, K;
node dp(int h, int sum, int rem, bool unlimit1, bool unlimit2)
{
if(h == 0) {
if(sum + rem >= K) return node(1, 0);
return node(0, sum + rem);
}
if(vis[h][sum][rem] && unlimit1 && unlimit2) return d[h][sum][rem];
node ans(0, rem);
int st = !unlimit1 ? digL[h] : 0;
int ed = !unlimit2 ? digR[h] : 9;
for(int i = st; i <= ed; i++)
ans += dp(h-1, sum + i, ans.res, (unlimit1 || i > digL[h]), (unlimit2 || i < digR[h]));
if(unlimit1 && unlimit2) {
d[h][sum][rem] = ans;
vis[h][sum][rem] = true;
}
return ans;
}
int main()
{
cin >> L >> R >> K;
while(L) {
digL[++digL[0]] = L % 10;
L /= 10;
}
while(R) {
digR[++digR[0]] = R % 10;
R /= 10;
}
node ans = dp(digR[0], 0, 0, 0, 0);
cout << ans.cnt;