1, 2, 3 - Decomposition
题目链接:ARC 123C
题目大意
给你一个数,你可以用一些每一位都是 1,2,3 其中一个的数加起来来得到它。
然后问你最少要用多少个数来加。
思路
考虑用数位 DP 来搞。
不过首先要枚举答案,再判断答案是否可行。
然后进行数位 DP,就是从低位往高位凑,那由于前导
0
0
0 是可以的,我们就会有一些数字从一些位置之后就停止填数。
那我们想我们肯定是能让他继续填更好啊。
那我们就这么设
f
i
,
j
f_{i,j}
fi,j 为填到
i
i
i 位,进位是
j
j
j,最多能留着多少个数。
然后就分能全留着和不能全留着两个转移。
(不能全留也要尽可能的留,所以都会选数字
1
1
1,能留到的就是要加的大小)
然后转移就可以啦,枚举到最小的可以的答案就退出咯。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
int T, a[21], nn;
ll n;
int in[21][11];
bool check(int mid) {
memset(in, -1, sizeof(in));
in[0][0] = mid;
for (int i = 0; i < nn; i++)//从低到高凑出每一位
for (int j = 0; j <= 9; j++)//之前的进位
if (in[i][j]) {
for (int k = 0; k <= 9; k++) {//这一位凑出什么
int nd = k * 10 + a[i + 1] - j;//需要加多少
if (in[i][j] <= nd && nd <= in[i][j] * 3) in[i + 1][k] = max(in[i + 1][k], in[i][j]);//能加到这个量
else if (nd >= 0 && nd <= in[i][j] * 3) in[i + 1][k] = max(in[i + 1][k], nd);//要多放入数
if (nd > mid * 3) break;//超过了最大,不可能凑得到了
}
}
return in[nn - 1][a[nn]] != -1 || in[nn][0] != -1;//怕它没进位(一个应该也行?)
}
int main() {
scanf("%d", &T);
while (T--) {
scanf("%lld", &n);
nn = 0;
while (n) {
a[++nn] = n % 10;
n /= 10;
}
int ans = 1;
while (1) {
if (check(ans)) break;
ans++;
}
printf("%d\n", ans);
}
return 0;
}