Let f(n) denote the number of ways to make the sum of n. When n > 3, the number of digits is greater than 1. The first digit d used must be one of 1, 2, 3 or 4. Remove the first digit, then the remaining sum is n-d. There are f(n-d) ways to make the sum of n-d, so we've found the recurrence of
f(n) = 2*f(n-1) + f(n-2) + f(n-3)
and the base cases are
f(1) = 2, f(2) = 5, f(3) = 13
Code:
- /*************************************************************************
- * Copyright (C) 2008 by liukaipeng *
- * liukaipeng at gmail dot com *
- *************************************************************************/
- /* @JUDGE_ID 00000 10198 C++ "Counting" */
- #include <algorithm>
- #include <cstdio>
- #include <cmath>
- #include <cstring>
- #include <deque>
- #include <fstream>
- #include <iostream>
- #include <list>
- #include <map>
- #include <queue>
- #include <set>
- #include <stack>
- #include <string>
- #include <vector>
- using namespace std;
- struct bignum
- {
- bignum(int v = 0) : start(max_digits)
- {
- bzero(digits, max_digits);
- assign(v);
- }
- bignum(char const *v) : start(max_digits)
- {
- bzero(digits, max_digits);
- assign(v);
- }
- void assign(int v)
- {
- start = max_digits;
- for (; v != 0; v /= 10) digits[--start] = v % 10;
- }
- void assign(char const *v)
- {
- start = max_digits - strlen(v);
- for (int i = start; i < max_digits; ++i)
- digits[i] = *v++ - '0';
- remove_leading_zero();
- }
- void convert(int& v) const
- {
- v = 0;
- for (int i = start; i < max_digits; ++i, v *= 10) v += digits[i];
- }
- void convert(char *v) const
- {
- for (int i = start; i < max_digits; ++i)
- *v++ = digits[i] + '0';
- *v = '/0';
- }
- bignum& operator+=(bignum const& other)
- {
- start = min(start, other.start) - 1;
- for (int i = max_digits - 1, carry = 0; i >= start; --i) {
- int s = digits[i] + other.digits[i] + carry;
- digits[i] = s % 10;
- carry = s / 10;
- }
- remove_leading_zero();
- return *this;
- }
- bignum operator+(bignum const& other) const
- {
- bignum tmp(*this);
- tmp += other;
- return tmp;
- }
- bool operator<(bignum const& other) const
- {
- if (start > other.start) return true;
- else if (start < other.start) return false;
- return memcmp(digits + start, other.digits + start, max_digits - start) < 0;
- }
- static int const max_digits = 500;
- char digits[max_digits];
- int start;
- private:
- void remove_leading_zero()
- {
- for (; digits[start] == 0 && start < max_digits; ++start) {}
- }
- };
- inline istream& operator>>(istream& is, bignum& n)
- {
- char buf[bignum::max_digits+1];
- is >> buf;
- n.assign(buf);
- return is;
- }
- inline ostream& operator<<(ostream& os, bignum const& n)
- {
- char buf[bignum::max_digits+1];
- n.convert(buf);
- os << buf;
- return os;
- }
- /*
- * Let f(n) denote the number of ways to make the sum of n. When n > 3, the number
- * of digits is greater than 1. The first digit d used must be one of 1, 2, 3 or 4.
- * Remove the first digit, then the remaining sum is n-d. There are f(n-d) ways to
- * make the sum of n-d, so we've found the recurrence of
- * f(n) = 2*f(n-1) + f(n-2) + f(n-3)
- * and the base cases are
- * f(1) = 2, f(2) = 5, f(3) = 13
- */
- void gen_numbers(bignum *numbers, int size)
- {
- numbers[1] = 2;
- numbers[2] = 5;
- numbers[3] = 13;
- for (int i = 4; i < size; ++i) {
- numbers[i] = numbers[i-1] + numbers[i-1];
- numbers[i] += numbers[i-2];
- numbers[i] += numbers[i-3];
- }
- }
- int main(int argc, char *argv[])
- {
- #ifndef ONLINE_JUDGE
- freopen((string(argv[0]) + ".in").c_str(), "r", stdin);
- freopen((string(argv[0]) + ".out").c_str(), "w", stdout);
- #endif
- int const size = 1001;
- bignum numbers[size];
- gen_numbers(numbers, size);
- for (int n; cin >> n; ) cout << numbers[n] << '/n';
- return 0;
- }