有 个火柴,用这些火柴能摆出非负整数,摆出的数不能有前导零,火柴不必用完,求方案总数。
链接
题解
首先考虑不存在数字 0 的情况,用 表示用 个火柴棒能摆出的方案总数,用 表示摆出数字 x 使用的火柴棒数量。
前导零是不被允许的,所以初始状态要把 1 ~ 9 几个数字的方案数加一。
每次递推用 去更新 (),表示在 表示的数字尾部添加一个 所得的方案。
递推计算完成后求出前缀和 即为答案,如果 则需要将答案加一(考虑单独的数字 0)。
需要使用高精度。
代码
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
const int MAXT = 100;
const int MAXN = 2000;
const int C[] = { 6, 2, 5, 5, 4, 5, 6, 3, 7, 6 };
struct BigInt {
std::vector<char> v;
BigInt() {}
BigInt(int x) {
*this = x;
}
BigInt &operator=(int x) {
v.clear();
do v.push_back(x % 10); while (x /= 10);
}
};
std::ostream &operator<<(std::ostream &out, const BigInt &x) {
const std::vector<char> &v = x.v;
for (int i = v.size() - 1; i >= 0; i--) out << (char)(v[i] + '0');
return out;
}
BigInt operator+(const BigInt &a, const BigInt &b) {
BigInt r;
r.v.reserve(std::max(a.v.size(), b.v.size()) + 1);
bool flag = false;
for (int i = 0; i < std::max(a.v.size(), b.v.size()); i++) {
int tmp = 0;
if (i < a.v.size()) tmp += a.v[i];
if (i < b.v.size()) tmp += b.v[i];
if (flag) tmp++, flag = false;
if (tmp >= 10) tmp -= 10, flag = true;
r.v.push_back(tmp);
}
if (flag) r.v.push_back(1);
return r;
}
BigInt &operator+=(BigInt &a, const BigInt &b) {
return a = a + b;
}
BigInt f[MAXN + 1], sum[MAXN + 1];
inline void makeTable() {
for (int i = 1; i < 10; i++) f[C[i]] += 1;
for (int i = 1; i <= MAXN; i++) {
for (int j = 0; j < 10; j++) {
if (i + C[j] <= MAXN) f[i + C[j]] += f[i];
}
}
sum[2] = f[2];
for (int i = 3; i <= MAXN; i++) sum[i] = sum[i - 1] + f[i];
}
int main() {
makeTable();
int n;
while (~scanf("%d", &n)) {
if (n == 0 || n == 1) puts("0");
else if (n < 6) std::cout << sum[n] << std::endl;
else std::cout << sum[n] + 1 << std::endl;
}
return 0;
}