10分做法
在 $n$ 不大于 $20$ 的情况下,我们肯定可以通过暴搜来完成这一部分,不过搜索写起来比较麻烦,我们可以换个思路。因为木棍只有 $20$ 个,而我们又可以很容易构造出 2222
这个数字,刚好使用这 $20$ 根火柴棍,那么显然,最终构成的数字是不会超过 $4$ 位数的,因此我们可以直接枚举数字本身,并计算拼出的数字需要的火柴棍数量,用一个桶记录最小值即可。
C++ 代码
#include <bits/stdc++.h>
using namespace std;
int nums[] = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6};
int calc(int x) {
int res = 0;
while (x) {
res += nums[x%10];
x /= 10;
}
return res;
}
int main() {
vector<int> f(21, -1);
for (int i = 1; i < 1e5; ++i) {
int x = calc(i);
if (f[x] == -1) f[x] = i;
}
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
cout << f[n] << '\n';
}
return 0;
}
30分做法 (特殊性质A贪心)
特殊性质A:保证 $n$ 是 $7$ 的倍数且 $n \geqslant 100$
由于 $n$ 是 $7$ 的倍数,我们观察到只有数字 $8$ 花费了 $7$ 根火柴棍。由于我们要求拼出的数字尽量小,那么拼出的数字的位数一定尽量小,那我们不妨让所有位置都塞满 $8$,这样一定可以保证拼出数字的位数花费最小。
满分算法(小范围枚举+大范围贪心)
由上述分析可知,我们可以一直放 $8$,直到放不下的情况稍作修改。那我们可以在小范围内用上述所示的枚举或dp进行计算,然后往这个结果后面放置若干个 $8$ 即可。因此,我们需要将 $n$ 表示为 $n = 7k+x$,然后输出 $x$ 根木棍能构造出的最小数字和 $k$ 个 $8$ 即可。
C++ 代码
#include <bits/stdc++.h>
using namespace std;
int nums[] = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6};
int calc(int x) {
int res = 0;
while (x) {
res += nums[x%10];
x /= 10;
}
return res;
}
int main() {
vector<int> f(30, -1);
for (int i = 1; i < 1e5; ++i) {
int x = calc(i);
if (f[x] == -1) f[x] = i;
}
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
int k = 0;
if (n > 20) {
k = (n-20)/7;
n -= 7*k;
}
cout << f[n];
for (int i = 1; i <= k; ++i) cout << "8";
cout << '\n';
}
return 0;
}