您的位置:首页 > 其它

UVa Problem Solution: 10198 - Counting

2008-11-27 16:36 561 查看
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';

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: