#include <algorithm>
#include <iterator>
#include <iostream>
#include <sstream>
#include <string>
#include <deque>
#include <map>

using namespace std;

typedef unsigned long ulong;

struct BigInt
{
    static const ulong base = 10000;
    static const ulong N = 4;

    deque<ulong> digits;

    BigInt();
    BigInt(string str);
    BigInt(ulong num);

    BigInt & operator  += (const BigInt & bi);
    BigInt & operator  -= (const BigInt & bi);
    BigInt & operator  *= (const BigInt & bi);
    BigInt & operator  *= (ulong n);
    BigInt & operator <<= (ulong n);

    BigInt operator  + (const BigInt & bi) const;
    BigInt operator  - (const BigInt & bi) const;
    BigInt operator  * (const BigInt & bi) const;
    BigInt operator  * (ulong n) const;
    BigInt operator << (ulong n) const;

    bool operator == (const BigInt & other) const;
    bool operator == (ulong other) const;

    void normalize();
};

typedef const BigInt & BICR;
typedef       BigInt & BIR;

struct Add { ulong operator()(ulong a, ulong b) { return a + b; } };

struct Mul
{
    ulong k;

    Mul() {}
    Mul(ulong n) : k(n) {}

    ulong operator()(ulong a) { return a * k; }
};

struct Carry
{
    ulong & carry;

    Carry(ulong & c) : carry(c) {}

    ulong operator()(ulong n)
    {
        n += carry;
        carry = n / BigInt::base;
        n %= BigInt::base;

        return n;
    }
};

template <class BaseOp>
struct OpWithCarry : public BaseOp, public Carry
{
    OpWithCarry(ulong & c) : Carry(c) {}

    ulong operator()(ulong a) { return Carry::operator()(BaseOp::operator()(a)); }
    ulong operator()(ulong a, ulong b) { return Carry::operator()(BaseOp::operator()(a, b)); }
};

struct Borrow
{
    long & borrow;

    Borrow(long & b) : borrow(b) {}

    ulong operator()(long n)
    {
        n -= borrow; borrow = 0;
        while (n < 0) { n += BigInt::base; ++borrow; }
        return n;
    }
};

struct SubWithBorrow
{
    long & borrow;

    SubWithBorrow(long & b) : borrow(b) {}

    ulong operator()(long a, long b)
    {
        long n = b - a - borrow;
        borrow = 0;
        while (n < 0) { n += BigInt::base; ++borrow; }
        return n;
    }
};

BigInt::BigInt() { digits.assign(1, 0); }

BigInt::BigInt(ulong num)
{
    stringstream buffer;
    buffer << num;
    *this = BigInt(buffer.str());
}

BigInt::BigInt(string str)
{
    reverse(str.begin(), str.end());

    while (str.size() % BigInt::N != 0)
        str.push_back('0');

    reverse(str.begin(), str.end());

    ulong pos = 0;
    ulong size = str.size();

    while (pos != size)
    {
        stringstream buffer(str.substr(pos, BigInt::N));
        ulong digit;
        buffer >> digit;
        digits.push_back(digit);

        pos += BigInt::N;
    }

    reverse(digits.begin(), digits.end());
}

BigInt & BigInt::operator += (BICR bi)
{
    if (digits.size() < bi.digits.size())
        digits.resize(bi.digits.size());

    ulong carry = 0;
    deque<ulong>::iterator it;

    OpWithCarry<Add> add_wc(carry);

    it = transform(bi.digits.begin(), bi.digits.end(),
        digits.begin(), digits.begin(), add_wc);

    transform(it, digits.end(), it, Carry(carry));

    if (carry) digits.push_back(carry);

    return *this;
}

BigInt & BigInt::operator -= (BICR bi)
{
    long borrow = 0;
    deque<ulong>::iterator it;

    it = transform(bi.digits.begin(), bi.digits.end(),
        digits.begin(), digits.begin(), SubWithBorrow(borrow));

    transform(it, digits.end(), it, Borrow(borrow));

    return *this;
}

BigInt & BigInt::operator *= (ulong n)
{
    ulong carry = 0;

    OpWithCarry<Mul> mul_wc(carry);
    mul_wc.k = n;

    transform(digits.begin(), digits.end(), digits.begin(), mul_wc);

    while (carry) { digits.push_back(carry % BigInt::base); carry /= BigInt::base; }

    return *this;
}

BigInt & BigInt::operator *= (BICR bi)
{
    const BigInt * max_op = this;
    const BigInt * min_op = &bi;

    ulong max_size = max_op->digits.size();
    ulong min_size = min_op->digits.size();

    if (max_size < min_size)
    {
        swap(max_op, min_op);
        swap(max_size, min_size);
    }

    deque<BigInt> array(min_size);

    for (ulong i = 0; i < min_size; ++i)
    {
        array[i].digits.resize(max_size);
        array[i] = *max_op * min_op->digits[i];
    }

    *this = array[0];
    digits.resize(max_size + min_size);

    for (ulong i = 1; i < min_size; ++i)
    {
        array[i] <<= i;
        *this += array[i];
    }

    return *this;
}

BigInt & BigInt::operator <<= (ulong n)
{
    digits.resize(digits.size() + n);

    copy(digits.rbegin() + n, digits.rend(), digits.rbegin());
    fill(digits.begin(), digits.begin() + n, 0);

    return *this;
}

BigInt BigInt::operator  + (BICR bi) const { BigInt result(*this); return (result  += bi); }
BigInt BigInt::operator  - (BICR bi) const { BigInt result(*this); return (result  -= bi); }
BigInt BigInt::operator  * (ulong n) const { BigInt result(*this); return (result  *=  n); }
BigInt BigInt::operator  * (BICR bi) const { BigInt result(*this); return (result  *= bi); }
BigInt BigInt::operator << (ulong n) const { BigInt result(*this); return (result <<=  n); }

bool BigInt::operator == (const BigInt & other) const
{
    return this->digits == other.digits;
}

bool BigInt::operator == (ulong other) const
{
    return *this == BigInt(other);
}

void BigInt::normalize()
{
    while (digits.size() > 1)
    {
        if (digits.back() == 0)
            digits.pop_back();
        else break;
    }
}

BigInt operator + (ulong n, BICR bi) { return bi + n; }
BigInt operator * (ulong n, BICR bi) { return bi * n; }

ostream & operator << (ostream & os, BICR bi)
{
    BIR bi_ = const_cast<BIR>(bi);
    bi_.normalize();

    long size = bi.digits.size();

    if (bi.digits[size - 1])
        os << bi.digits[size - 1];

    for (long i = size - 2; i >= 0; --i)
    {
        stringstream buffer;
        buffer << bi.digits[i];

        string str = buffer.str();

        ulong toN = BigInt::N - str.size();
        if (toN > 0)
            str = string(toN, '0') + str;

        os << str;
    }

    return os;
}

BigInt fact(ulong n)
{
    static map<ulong, BigInt> cache;
    static map<ulong, BigInt>::iterator it;

    if (n == 0) return 1;

    it = cache.find(n);

    if (it != cache.end())
        return it->second;
    else
        return cache[n] = n * fact(n - 1);
}

BigInt A_func(ulong n)
{
    static map<ulong, BigInt> cache;
    static map<ulong, BigInt>::iterator it;

    if (n == 1) return 7;
    if (n == 2) return 2;
    if (n == 3) return 1;

    it = cache.find(n);

    if (it != cache.end())
        return it->second;
    else
        return cache[n] =   fact(n + 1) * A_func(n - 1) +
                                      5 * A_func(n - 2) +
                                      7 * A_func(n - 3);
}

void init_array(BigInt A_arr[], ulong size)
{
    for (ulong i = 0; i < size; ++i)
    {
        A_arr[i] = A_func(i + 1);
    }
}

void print_array(BigInt A_arr[], ulong size)
{
    for (ulong i = 0; i < size; ++i)
    {
        cout << "A(" << i + 1 << ") = " << A_arr[i] << endl;
    }
}

int main()
{
    BigInt A_arr[50];

    init_array(A_arr, 50);
    print_array(A_arr, 50);

    return 0;
}
