/ Team SD /

用户

个人简介

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <cctype>
#include <cmath>
#include <sstream>
#include <stdexcept>

using namespace std;

class HighPrecisionInt {
private:
    vector<int> digits;
    bool isNegative;

    void removeLeadingZeros() {
        while (digits.size() > 1 && digits.back() == 0) {
            digits.pop_back();
        }
        if (digits.size() == 1 && digits[0] == 0) {
            isNegative = false;
        }
    }

    HighPrecisionInt absolute() const {
        HighPrecisionInt res = *this;
        res.isNegative = false;
        return res;
    }

public:
    HighPrecisionInt() : isNegative(false) {
        digits.push_back(0);
    }

    HighPrecisionInt(const string& numStr) : isNegative(false) {
        size_t start = 0;
        if (numStr.empty()) {
            digits.push_back(0);
            return;
        }
        if (numStr[0] == '-') {
            isNegative = true;
            start = 1;
        } else if (numStr[0] == '+') {
            start = 1;
        }
        for (size_t i = numStr.size() - 1; i >= start; --i) {
            if (!isdigit(numStr[i])) {
                throw invalid_argument("Invalid integer string");
            }
            digits.push_back(numStr[i] - '0');
        }
        removeLeadingZeros();
    }

    HighPrecisionInt(long long num) : isNegative(false) {
        if (num < 0) {
            isNegative = true;
            num = -num;
        }
        if (num == 0) {
            digits.push_back(0);
            return;
        }
        while (num > 0) {
            digits.push_back(num % 10);
            num /= 10;
        }
    }

    string toString() const {
        if (digits.empty()) return "0";
        string res;
        if (isNegative) res += '-';
        for (auto it = digits.rbegin(); it != digits.rend(); ++it) {
            res += char('0' + *it);
        }
        return res.empty() ? "0" : res;
    }

    HighPrecisionInt operator+(const HighPrecisionInt& other) const {
        HighPrecisionInt result;
        if (isNegative == other.isNegative) {
            result.isNegative = isNegative;
            int carry = 0;
            size_t i = 0;
            while (i < digits.size() || i < other.digits.size() || carry) {
                int sum = carry;
                if (i < digits.size()) sum += digits[i];
                if (i < other.digits.size()) sum += other.digits[i];
                carry = sum / 10;
                result.digits.push_back(sum % 10);
                ++i;
            }
        } else {
            if (absolute() >= other.absolute()) {
                result.isNegative = isNegative;
                int borrow = 0;
                size_t i = 0;
                while (i < digits.size() || i < other.digits.size()) {
                    int diff = borrow;
                    if (i < digits.size()) diff += digits[i];
                    if (i < other.digits.size()) diff -= other.digits[i];
                    if (diff < 0) {
                        diff += 10;
                        borrow = -1;
                    } else {
                        borrow = 0;
                    }
                    result.digits.push_back(diff);
                    ++i;
                }
            } else {
                result.isNegative = other.isNegative;
                int borrow = 0;
                size_t i = 0;
                while (i < digits.size() || i < other.digits.size()) {
                    int diff = borrow;
                    if (i < other.digits.size()) diff += other.digits[i];
                    if (i < digits.size()) diff -= digits[i];
                    if (diff < 0) {
                        diff += 10;
                        borrow = -1;
                    } else {
                        borrow = 0;
                    }
                    result.digits.push_back(diff);
                    ++i;
                }
            }
        }
        result.removeLeadingZeros();
        return result;
    }

    HighPrecisionInt operator-(const HighPrecisionInt& other) const {
        HighPrecisionInt temp = other;
        temp.isNegative = !temp.isNegative;
        return *this + temp;
    }

    HighPrecisionInt operator*(const HighPrecisionInt& other) const {
        HighPrecisionInt result;
        result.digits.resize(digits.size() + other.digits.size(), 0);
        result.isNegative = isNegative != other.isNegative;

        for (size_t i = 0; i < digits.size(); ++i) {
            int carry = 0;
            for (size_t j = 0; j < other.digits.size() || carry; ++j) {
                long long product = result.digits[i + j] + carry;
                if (j < other.digits.size()) {
                    product += (long long)digits[i] * other.digits[j];
                }
                result.digits[i + j] = product % 10;
                carry = product / 10;
            }
        }

        result.removeLeadingZeros();
        return result;
    }

    HighPrecisionInt operator/(const HighPrecisionInt& other) const {
        if (other.isZero()) {
            throw runtime_error("Division by zero");
        }

        HighPrecisionInt dividend = absolute();
        HighPrecisionInt divisor = other.absolute();
        HighPrecisionInt quotient;
        HighPrecisionInt remainder;

        if (dividend < divisor) {
            return HighPrecisionInt(0);
        }

        quotient.digits.reserve(dividend.digits.size());
        size_t i = dividend.digits.size();
        while (i > 0) {
            --i;
            remainder = remainder * HighPrecisionInt(10) + HighPrecisionInt(dividend.digits[i]);
            int count = 0;
            while (remainder >= divisor) {
                remainder = remainder - divisor;
                ++count;
            }
            quotient.digits.push_back(count);
        }

        reverse(quotient.digits.begin(), quotient.digits.end());
        quotient.isNegative = isNegative != other.isNegative;
        quotient.removeLeadingZeros();
        return quotient;
    }

    HighPrecisionInt operator%(const HighPrecisionInt& other) const {
        if (other.isZero()) {
            throw runtime_error("Modulo by zero");
        }

        HighPrecisionInt dividend = absolute();
        HighPrecisionInt divisor = other.absolute();
        HighPrecisionInt remainder;

        if (dividend < divisor) {
            remainder = dividend;
        } else {
            size_t i = dividend.digits.size();
            while (i > 0) {
                --i;
                remainder = remainder * HighPrecisionInt(10) + HighPrecisionInt(dividend.digits[i]);
                while (remainder >= divisor) {
                    remainder = remainder - divisor;
                }
            }
        }

        remainder.isNegative = isNegative;
        remainder.removeLeadingZeros();
        return remainder;
    }

    HighPrecisionInt& operator+=(const HighPrecisionInt& other) {
        *this = *this + other;
        return *this;
    }

    HighPrecisionInt& operator-=(const HighPrecisionInt& other) {
        *this = *this - other;
        return *this;
    }

    HighPrecisionInt& operator*=(const HighPrecisionInt& other) {
        *this = *this * other;
        return *this;
    }

    HighPrecisionInt& operator/=(const HighPrecisionInt& other) {
        *this = *this / other;
        return *this;
    }

    HighPrecisionInt& operator%=(const HighPrecisionInt& other) {
        *this = *this % other;
        return *this;
    }

    HighPrecisionInt operator-() const {
        HighPrecisionInt res = *this;
        if (!res.isZero()) {
            res.isNegative = !res.isNegative;
        }
        return res;
    }

    HighPrecisionInt operator++() {
        *this += HighPrecisionInt(1);
        return *this;
    }

    HighPrecisionInt operator++(int) {
        HighPrecisionInt temp = *this;
        *this += HighPrecisionInt(1);
        return temp;
    }

    HighPrecisionInt operator--() {
        *this -= HighPrecisionInt(1);
        return *this;
    }

    HighPrecisionInt operator--(int) {
        HighPrecisionInt temp = *this;
        *this -= HighPrecisionInt(1);
        return temp;
    }

    bool operator==(const HighPrecisionInt& other) const {
        if (isNegative != other.isNegative) return false;
        if (digits.size() != other.digits.size()) return false;
        for (size_t i = 0; i < digits.size(); ++i) {
            if (digits[i] != other.digits[i]) return false;
        }
        return true;
    }

    bool operator!=(const HighPrecisionInt& other) const {
        return !(*this == other);
    }

    bool operator>(const HighPrecisionInt& other) const {
        if (isNegative != other.isNegative) {
            return !isNegative;
        }
        if (isNegative) {
            return absolute() < other.absolute();
        } else {
            if (digits.size() != other.digits.size()) {
                return digits.size() > other.digits.size();
            }
            for (size_t i = digits.size(); i > 0; --i) {
                if (digits[i - 1] != other.digits[i - 1]) {
                    return digits[i - 1] > other.digits[i - 1];
                }
            }
            return false;
        }
    }

    bool operator<(const HighPrecisionInt& other) const {
        return other > *this;
    }

    bool operator>=(const HighPrecisionInt& other) const {
        return !(*this < other);
    }

    bool operator<=(const HighPrecisionInt& other) const {
        return !(*this > other);
    }

    bool isZero() const {
        return digits.size() == 1 && digits[0] == 0 && !isNegative;
    }

    HighPrecisionInt pow(const HighPrecisionInt& exponent) const {
        if (exponent.isNegative()) {
            throw invalid_argument("Exponent cannot be negative");
        }
        if (exponent.isZero()) {
            return HighPrecisionInt(1);
        }
        if (*this == HighPrecisionInt(0)) {
            return HighPrecisionInt(0);
        }

        HighPrecisionInt result(1);
        HighPrecisionInt base = *this;
        HighPrecisionInt exp = exponent;

        while (exp > HighPrecisionInt(0)) {
            if (exp % HighPrecisionInt(2) == HighPrecisionInt(1)) {
                result *= base;
            }
            base *= base;
            exp /= HighPrecisionInt(2);
        }

        return result;
    }

    HighPrecisionInt gcd(const HighPrecisionInt& other) const {
        HighPrecisionInt a = absolute();
        HighPrecisionInt b = other.absolute();
        while (!b.isZero()) {
            HighPrecisionInt temp = b;
            b = a % b;
            a = temp;
        }
        return a;
    }

    HighPrecisionInt lcm(const HighPrecisionInt& other) const {
        if (isZero() || other.isZero()) {
            return HighPrecisionInt(0);
        }
        return (*this * other).absolute() / gcd(other);
    }

    bool isNegative() const {
        return isNegative;
    }

    size_t length() const {
        return digits.size();
    }

    HighPrecisionInt factorial() const {
        if (isNegative()) {
            throw invalid_argument("Factorial of negative number is undefined");
        }
        HighPrecisionInt result(1);
        HighPrecisionInt num = *this;
        while (num > HighPrecisionInt(0)) {
            result *= num;
            --num;
        }
        return result;
    }

    vector<int> getDigits() const {
        return digits;
    }

    friend ostream& operator<<(ostream& os, const HighPrecisionInt& num) {
        os << num.toString();
        return os;
    }

    friend istream& operator>>(istream& is, HighPrecisionInt& num) {
        string s;
        is >> s;
        num = HighPrecisionInt(s);
        return is;
    }
};

class HighPrecisionDecimal {
private:
    HighPrecisionInt integerPart;
    vector<int> fractionalPart;
    size_t precision;

    void removeTrailingZeros() {
        while (fractionalPart.size() > 0 && fractionalPart.back() == 0) {
            fractionalPart.pop_back();
        }
        if (fractionalPart.empty() && integerPart.isZero()) {
            fractionalPart.push_back(0);
        }
        if (precision > 0 && fractionalPart.size() > precision) {
            roundToPrecision(precision);
        }
    }

    void roundToPrecision(size_t prec) {
        if (fractionalPart.size() <= prec) {
            while (fractionalPart.size() < prec) {
                fractionalPart.push_back(0);
            }
            return;
        }

        int carry = fractionalPart[prec] >= 5 ? 1 : 0;
        fractionalPart.resize(prec);

        if (carry > 0) {
            HighPrecisionInt temp(1);
            integerPart += temp;
        }

        removeTrailingZeros();
    }

public:
    HighPrecisionDecimal(size_t prec = 100) : precision(prec) {
        fractionalPart.push_back(0);
    }

    HighPrecisionDecimal(const string& numStr, size_t prec = 100) : precision(prec) {
        size_t dotPos = numStr.find('.');
        string intStr, fracStr;

        if (dotPos == string::npos) {
            intStr = numStr;
            fracStr = "";
        } else {
            intStr = numStr.substr(0, dotPos);
            fracStr = numStr.substr(dotPos + 1);
        }

        integerPart = HighPrecisionInt(intStr);

        for (char c : fracStr) {
            if (!isdigit(c)) {
                throw invalid_argument("Invalid decimal string");
            }
            fractionalPart.push_back(c - '0');
        }

        removeTrailingZeros();
        if (fractionalPart.size() > precision) {
            roundToPrecision(precision);
        }
    }

    HighPrecisionDecimal(long long num, size_t prec = 100) : integerPart(num), precision(prec) {
        fractionalPart.push_back(0);
    }

    HighPrecisionDecimal(const HighPrecisionInt& intPart, size_t prec = 100) : integerPart(intPart), precision(prec) {
        fractionalPart.push_back(0);
    }

    string toString() const {
        string res = integerPart.toString();
        if (!fractionalPart.empty() && !(fractionalPart.size() == 1 && fractionalPart[0] == 0)) {
            res += '.';
            for (auto it = fractionalPart.rbegin(); it != fractionalPart.rend(); ++it) {
                res += char('0' + *it);
            }
        }
        return res;
    }

    string toScientificNotation() const {
        string intStr = integerPart.toString();
        bool isNeg = integerPart.isNegative();
        string absIntStr = isNeg ? intStr.substr(1) : intStr;

        string sigFigs;
        size_t exp;

        if (absIntStr == "0") {
            size_t firstNonZero = 0;
            while (firstNonZero < fractionalPart.size() && fractionalPart[firstNonZero] == 0) {
                ++firstNonZero;
            }
            if (firstNonZero == fractionalPart.size()) {
                return "0e0";
            }
            sigFigs += char('0' + fractionalPart[firstNonZero]);
            sigFigs += '.';
            for (size_t i = firstNonZero + 1; i < fractionalPart.size() && i < firstNonZero + 1 + precision; ++i) {
                sigFigs += char('0' + fractionalPart[i]);
            }
            exp = -(firstNonZero + 1);
        } else {
            sigFigs += absIntStr[0];
            if (absIntStr.size() > 1) {
                sigFigs += '.';
                sigFigs += absIntStr.substr(1);
            }
            for (size_t i = 0; i < fractionalPart.size() && sigFigs.size() - (absIntStr.size() > 1 ? 2 : 1) < precision; ++i) {
                sigFigs += char('0' + fractionalPart[i]);
            }
            exp = absIntStr.size() - 1;
        }

        string res;
        if (isNeg) res += '-';
        res += sigFigs;
        res += 'e';
        res += to_string(exp);
        return res;
    }

    HighPrecisionDecimal operator+(const HighPrecisionDecimal& other) const {
        HighPrecisionDecimal result(precision > other.precision ? precision : other.precision);

        size_t maxFracSize = max(fractionalPart.size(), other.fractionalPart.size());
        vector<int> tempFrac(maxFracSize + 1, 0);
        int carry = 0;

        for (size_t i = 0; i < maxFracSize; ++i) {
            int sum = carry;
            if (i < fractionalPart.size()) sum += fractionalPart[i];
            if (i < other.fractionalPart.size()) sum += other.fractionalPart[i];
            tempFrac[i] = sum % 10;
            carry = sum / 10;
        }

        result.integerPart = integerPart + other.integerPart + HighPrecisionInt(carry);

        result.fractionalPart.clear();
        for (size_t i = 0; i < maxFracSize; ++i) {
            result.fractionalPart.push_back(tempFrac[i]);
        }

        result.removeTrailingZeros();
        return result;
    }

    HighPrecisionDecimal operator-(const HighPrecisionDecimal& other) const {
        HighPrecisionDecimal temp = other;
        temp.integerPart = -temp.integerPart;
        return *this + temp;
    }

    HighPrecisionDecimal operator*(const HighPrecisionDecimal& other) const {
        size_t newPrecision = precision + other.precision;
        HighPrecisionDecimal result(newPrecision);

        HighPrecisionInt intProduct = integerPart * other.integerPart;

        HighPrecisionInt fracInt1(0);
        for (auto it = fractionalPart.rbegin(); it != fractionalPart.rend(); ++it) {
            fracInt1 = fracInt1 * HighPrecisionInt(10) + HighPrecisionInt(*it);
        }

        HighPrecisionInt fracInt2(0);
        for (auto it = other.fractionalPart.rbegin(); it != other.fractionalPart.rend(); ++it) {
            fracInt2 = fracInt2 * HighPrecisionInt(10) + HighPrecisionInt(*it);
        }

        HighPrecisionInt fracProduct = fracInt1 * fracInt2;

        string fracProdStr = fracProduct.toString();
        size_t totalFracDigits = fractionalPart.size() + other.fractionalPart.size();
        while (fracProdStr.size() < totalFracDigits) {
            fracProdStr = "0" + fracProdStr;
        }

        string newIntStr, newFracStr;
        if (fracProdStr.size() > totalFracDigits) {
            newIntStr = fracProdStr.substr(0, fracProdStr.size() - totalFracDigits);
            newFracStr = fracProdStr.substr(fracProdStr.size() - totalFracDigits);
        } else {
            newIntStr = "0";
            newFracStr = fracProdStr;
        }

        HighPrecisionInt cross1 = integerPart * fracInt2;
        HighPrecisionInt cross2 = other.integerPart * fracInt1;
        HighPrecisionInt crossSum = cross1 + cross2;
        string crossSumStr = crossSum.toString();
        if (crossSumStr.size() > other.fractionalPart.size()) {
            newIntStr = (HighPrecisionInt(newIntStr) + HighPrecisionInt(crossSumStr.substr(0, crossSumStr.size() - other.fractionalPart.size()))).toString();
            newFracStr = crossSumStr.substr(crossSumStr.size() - other.fractionalPart.size()) + newFracStr;
        } else {
            while (crossSumStr.size() < other.fractionalPart.size()) {
                crossSumStr = "0" + crossSumStr;
            }
            newFracStr = crossSumStr + newFracStr;
        }

        result.integerPart = intProduct + HighPrecisionInt(newIntStr);

        result.fractionalPart.clear();
        for (size_t i = newFracStr.size(); i > 0; --i) {
            result.fractionalPart.push_back(newFracStr[i - 1] - '0');
        }

        result.removeTrailingZeros();
        return result;
    }

    HighPrecisionDecimal operator/(const HighPrecisionDecimal& other) const {
        if (other.isZero()) {
            throw runtime_error("Division by zero");
        }

        HighPrecisionDecimal dividend = *this;
        HighPrecisionDecimal divisor = other;

        HighPrecisionInt dividendInt = dividend.integerPart;
        HighPrecisionInt divisorInt = divisor.integerPart;

        size_t shift = 0;
        while (divisorInt.isZero() || (dividendInt < divisorInt && !dividendInt.isZero())) {
            divisor.shiftLeft(1);
            shift++;
            divisorInt = divisor.integerPart;
        }

        HighPrecisionDecimal quotient(precision);
        HighPrecisionDecimal remainder(precision);

        HighPrecisionInt currentInt = dividendInt;
        vector<int> currentFrac = dividend.fractionalPart;

        for (size_t i = 0; i <= precision; ++i) {
            int digit = 0;
            while (currentInt > divisorInt || (currentInt == divisorInt && remainder.isZero())) {
                currentInt -= divisorInt;
                digit++;
            }

            if (i < precision) {
                quotient.fractionalPart.push_back(digit);
            }

            if (i < currentFrac.size()) {
                currentInt = currentInt * HighPrecisionInt(10) + HighPrecisionInt(currentFrac[i]);
            } else {
                currentInt = currentInt * HighPrecisionInt(10);
            }
        }

        reverse(quotient.fractionalPart.begin(), quotient.fractionalPart.end());
        quotient.integerPart = HighPrecisionInt(0);
        quotient.removeTrailingZeros();

        for (size_t i = 0; i < shift; ++i) {
            quotient.shiftRight(1);
        }

        return quotient;
    }

    HighPrecisionDecimal& operator+=(const HighPrecisionDecimal& other) {
        *this = *this + other;
        return *this;
    }

    HighPrecisionDecimal& operator-=(const HighPrecisionDecimal& other) {
        *this = *this - other;
        return *this;
    }

    HighPrecisionDecimal& operator*=(const HighPrecisionDecimal& other) {
        *this = *this * other;
        return *this;
    }

    HighPrecisionDecimal& operator/=(const HighPrecisionDecimal& other) {
        *this = *this / other;
        return *this;
    }

    HighPrecisionDecimal operator-() const {
        HighPrecisionDecimal res = *this;
        res.integerPart = -res.integerPart;
        return res;
    }

    bool operator==(const HighPrecisionDecimal& other) const {
        if (integerPart != other.integerPart) return false;

        size_t maxFracSize = max(fractionalPart.size(), other.fractionalPart.size());
        for (size_t i = 0; i < maxFracSize; ++i) {
            int d1 = (i < fractionalPart.size()) ? fractionalPart[i] : 0;
            int d2 = (i < other.fractionalPart.size()) ? other.fractionalPart[i] : 0;
            if (d1 != d2) return false;
        }
        return true;
    }

    bool operator!=(const HighPrecisionDecimal& other) const {
        return !(*this == other);
    }

    bool operator>(const HighPrecisionDecimal& other) const {
        if (integerPart != other.integerPart) {
            return integerPart > other.integerPart;
        }

        size_t maxFracSize = max(fractionalPart.size(), other.fractionalPart.size());
        for (size_t i = 0; i < maxFracSize; ++i) {
            int d1 = (i < fractionalPart.size()) ? fractionalPart[i] : 0;
            int d2 = (i < other.fractionalPart.size()) ? other.fractionalPart[i] : 0;
            if (d1 != d2) {
                return d1 > d2;
            }
        }
        return false;
    }

    bool operator<(const HighPrecisionDecimal& other) const {
        return other > *this;
    }

    bool operator>=(const HighPrecisionDecimal& other) const {
        return !(*this < other);
    }

    bool operator<=(const HighPrecisionDecimal& other) const {
        return !(*this > other);
    }

    bool isZero() const {
        return integerPart.isZero() && fractionalPart.size() == 1 && fractionalPart[0] == 0;
    }

    void setPrecision(size_t prec) {
        precision = prec;
        removeTrailingZeros();
    }

    size_t getPrecision() const {
        return precision;
    }

    HighPrecisionInt getIntegerPart() const {
        return integerPart;
    }

    vector<int> getFractionalPart() const {
        return fractionalPart;
    }

    HighPrecisionDecimal pow(const HighPrecisionInt& exponent) const {
        if (exponent.isNegative()) {
            HighPrecisionDecimal one("1", precision);
            return one / pow(-exponent);
        }

        HighPrecisionDecimal result("1", precision);
        HighPrecisionDecimal base = *this;
        HighPrecisionInt exp = exponent;

        while (exp > HighPrecisionInt(0)) {
            if (exp % HighPrecisionInt(2) == HighPrecisionInt(1)) {
                result *= base;
            }
            base *= base;
            exp /= HighPrecisionInt(2);
        }

        return result;
    }

    HighPrecisionDecimal sqrt() const {
        if (integerPart.isNegative()) {
            throw invalid_argument("Square root of negative number is undefined");
        }
        if (isZero()) {
            return HighPrecisionDecimal("0", precision);
        }

        HighPrecisionDecimal low("0", precision);
        HighPrecisionDecimal high = *this;
        if (high < HighPrecisionDecimal("1", precision)) {
            high = HighPrecisionDecimal("1", precision);
        }

        HighPrecisionDecimal eps("1", precision);
        eps = eps.pow(HighPrecisionInt(precision + 1));

        for (size_t i = 0; i < precision * 2; ++i) {
            HighPrecisionDecimal mid = (low + high) / HighPrecisionDecimal("2", precision);
            HighPrecisionDecimal midSq = mid * mid;

            if (midSq > *this) {
                high = mid;
            } else {
                low = mid;
            }

            if (high - low < eps) {
                break;
            }
        }

        return (low + high) / HighPrecisionDecimal("2", precision);
    }

    void shiftLeft(size_t n) {
        for (size_t i = 0; i < n; ++i) {
            if (!fractionalPart.empty()) {
                integerPart = integerPart * HighPrecisionInt(10) + HighPrecisionInt(fractionalPart.back());
                fractionalPart.pop_back();
            } else {
                integerPart = integerPart * HighPrecisionInt(10);
            }
        }
        removeTrailingZeros();
    }

    void shiftRight(size_t n) {
        for (size_t i = 0; i < n; ++i) {
            fractionalPart.push_back(integerPart % HighPrecisionInt(10).getDigits()[0]);
            integerPart /= HighPrecisionInt(10);
        }
        removeTrailingZeros();
    }

    friend ostream& operator<<(ostream& os, const HighPrecisionDecimal& num) {
        os << num.toString();
        return os;
    }

    friend istream& operator>>(istream& is, HighPrecisionDecimal& num) {
        string s;
        is >> s;
        num = HighPrecisionDecimal(s, num.precision);
        return is;
    }
};

HighPrecisionInt factorialSeriesSum(const HighPrecisionInt& n) {
    HighPrecisionInt sum(0);
    HighPrecisionInt current(1);
    for (HighPrecisionInt i(0); i <= n; ++i) {
        sum += current;
        if (i < n) {
            current *= (i + HighPrecisionInt(1));
        }
    }
    return sum;
}

HighPrecisionDecimal pi(size_t precision) {
    HighPrecisionDecimal result("0", precision);
    HighPrecisionDecimal sign("1", precision);
    HighPrecisionDecimal denominator("1", precision);
    HighPrecisionDecimal four("4", precision);

    for (size_t i = 0; i < precision * 2; ++i) {
        result += sign * four / denominator;
        sign = -sign;
        denominator += HighPrecisionDecimal("2", precision);
    }

    return result;
}

HighPrecisionDecimal eulerNumber(size_t precision) {
    HighPrecisionDecimal result("0", precision);
    HighPrecisionDecimal factorial("1", precision);

    for (size_t i = 0; i < precision * 2; ++i) {
        result += HighPrecisionDecimal("1", precision) / factorial;
        if (i > 0) {
            factorial *= HighPrecisionDecimal(to_string(i), precision);
        }
    }

    return result;
}

HighPrecisionDecimal goldenRatio(size_t precision) {
    HighPrecisionDecimal five("5", precision);
    HighPrecisionDecimal sqrtFive = five.sqrt();
    HighPrecisionDecimal two("2", precision);
    return (HighPrecisionDecimal("1", precision) + sqrtFive) / two;
}

void demonstrateHighPrecisionInt() {
    cout << "=== High Precision Integer Demonstration ===" << endl;

    HighPrecisionInt a("123456789012345678901234567890");
    HighPrecisionInt b("987654321098765432109876543210");

    cout << "a = " << a << endl;
    cout << "b = " << b << endl;
    cout << "a + b = " << a + b << endl;
    cout << "a - b = " << a - b << endl;
    cout << "a * b = " << a * b << endl;
    cout << "a / b = " << a / b << endl;
    cout << "a % b = " << a % b << endl;

    HighPrecisionInt c("2");
    HighPrecisionInt d("100");
    cout << "2^100 = " << c.pow(d) << endl;

    HighPrecisionInt e("100");
    cout << "100! = " << e.factorial() << endl;

    HighPrecisionInt f("12345");
    HighPrecisionInt g("7890");
    cout << "gcd(12345, 7890) = " << f.gcd(g) << endl;
    cout << "lcm(12345, 7890) = " << f.lcm(g) << endl;

    cout << endl;
}

void demonstrateHighPrecisionDecimal() {
    cout << "=== High Precision Decimal Demonstration ===" << endl;

    HighPrecisionDecimal a("1234567890.12345678901234567890", 50);
    HighPrecisionDecimal b("9876543210.98765432109876543210", 50);

    cout << "a = " << a << endl;
    cout << "b = " << b << endl;
    cout << "a + b = " << a + b << endl;
    cout << "a - b = " << a - b << endl;
    cout << "a * b = " << a * b << endl;
    cout << "a / b = " << a / b << endl;

    HighPrecisionDecimal c("2.0", 50);
    HighPrecisionInt d("10");
    cout << "2.0^10 = " << c.pow(d) << endl;

    HighPrecisionDecimal e("2.0", 50);
    cout << "sqrt(2.0) = " << e.sqrt() << endl;

    cout << "pi (50 digits) = " << pi(50) << endl;
    cout << "e (50 digits) = " << eulerNumber(50) << endl;
    cout << "Golden ratio (50 digits) = " << goldenRatio(50) << endl;

    cout << "pi in scientific notation: " << pi(50).toScientificNotation() << endl;

    cout << endl;
}

int main() {
    demonstrateHighPrecisionInt();
    demonstrateHighPrecisionDecimal();

    cout << "=== Advanced Calculations ===" << endl;
    HighPrecisionInt largeFactorialInput("200");
    cout << "Sum of factorials from 0! to 200! = " << factorialSeriesSum(largeFactorialInput) << endl;

    HighPrecisionDecimal preciseCalculation("0.1234567890123456789012345678901234567890", 100);
    preciseCalculation = preciseCalculation.pow(HighPrecisionInt(5));
    cout << "0.123456789...^5 (100 digits) = " << preciseCalculation << endl;

    return 0;
}