-
个人简介
高精度一只
#ifndef BIGINT_H #define BIGINT_H #include <string> #include <vector> #include <stdexcept> #include <algorithm> #include <climits> #include <cctype> #include <cstdint> #include <cmath> #include <iostream> #include <cctype> #include <cstdlib> class bigint { public: bigint() : isNegative(false), digits({0}) {} // Construct from 64-bit integer bigint(int64_t num) { if (num == LLONG_MIN) { // Special handling for minimal long value digits = {223372036, 854775808}; // -2^63 in base 10^9 isNegative = true; return; } if (num < 0) { isNegative = true; num = -num; } else { isNegative = false; } if (num == 0) { digits = {0}; return; } // Convert to base 10^9 digits while (num > 0) { digits.push_back(num % BASE); num /= BASE; } std::reverse(digits.begin(), digits.end()); removeLeadingZeros(); } // Construct from string bigint(const std::string &str) { if (str.empty()) { digits = {0}; isNegative = false; return; } size_t start = 0; if (str[0] == '-') { isNegative = true; start = 1; } else { isNegative = false; } // Skip leading zeros while (start < str.size() && str[start] == '0') { start++; } if (start == str.size()) { digits = {0}; isNegative = false; return; } // Process digits in chunks of 9 for (size_t i = str.size(); i > start; i -= DIGITS_PER_ELEMENT) { size_t chunkStart = (i >= DIGITS_PER_ELEMENT) ? (i - DIGITS_PER_ELEMENT) : start; std::string chunk = str.substr(chunkStart, i - chunkStart); digits.push_back(std::stoul(chunk)); } std::reverse(digits.begin(), digits.end()); removeLeadingZeros(); } // Copy and move constructors bigint(const bigint &other) = default; bigint(bigint &&other) = default; // Assignment operators bigint &operator=(const bigint &other) = default; bigint &operator=(bigint &&other) = default; ~bigint() = default; // Read from input stream static bigint read(std::istream &is) { std::string s; is >> s; return bigint(s); } // Arithmetic operations bigint operator-() const; bigint operator+(const bigint &other) const; bigint operator-(const bigint &other) const; bigint operator*(const bigint &other) const; bigint operator/(const bigint &other) const; bigint operator%(const bigint &other) const; // Compound assignment operators bigint &operator+=(const bigint &other); bigint &operator-=(const bigint &other); bigint &operator*=(const bigint &other); bigint &operator/=(const bigint &other); bigint &operator%=(const bigint &other); // Comparison operators bool operator==(const bigint &other) const; bool operator!=(const bigint &other) const; bool operator<(const bigint &other) const; bool operator<=(const bigint &other) const; bool operator>(const bigint &other) const; bool operator>=(const bigint &other) const; // Conversion operators explicit operator std::string() const; explicit operator int64_t() const; explicit operator bool() const; // Utility functions void print() const; bigint abs() const; bool isZero() const; // Data members bool isNegative; std::vector<uint32_t> digits; // Constants for base 10^9 representation static const uint64_t BASE = 1000000000; // 10^9 base static const size_t DIGITS_PER_ELEMENT = 9; private: // Internal helpers void removeLeadingZeros(); int compare(const bigint &other) const; // Arithmetic implementations bigint add(const bigint &other) const; bigint subtract(const bigint &other) const; bigint multiply(const bigint &other) const; // Division helpers bigint divide(const bigint &other) const; bigint mod(const bigint &other) const; // Karatsuba multiplication components bigint karatsuba(const bigint &x, const bigint &y) const; bigint shiftLeft(size_t n) const; }; // Remove leading zero digits void bigint::removeLeadingZeros() { auto it = digits.begin(); while (it != digits.end() - 1 && *it == 0) { ++it; } digits.erase(digits.begin(), it); if (digits.empty()) { digits.push_back(0); } } // Compare two bigints (-1: this < other, 0: equal, 1: this > other) int bigint::compare(const bigint &other) const { if (isNegative != other.isNegative) { return isNegative ? -1 : 1; } if (digits.size() != other.digits.size()) { bool comp = digits.size() < other.digits.size(); return isNegative ? (comp ? 1 : -1) : (comp ? -1 : 1); } for (size_t i = 0; i < digits.size(); i++) { if (digits[i] != other.digits[i]) { bool comp = digits[i] < other.digits[i]; return isNegative ? (comp ? 1 : -1) : (comp ? -1 : 1); } } return 0; } // Unary minus operator bigint bigint::operator-() const { bigint result = *this; if (!isZero()) { result.isNegative = !isNegative; } return result; } // Addition operator bigint bigint::operator+(const bigint &other) const { if (isNegative == other.isNegative) { bigint result = add(other); result.isNegative = isNegative; return result; } if (abs() < other.abs()) { bigint result = other.subtract(*this); result.isNegative = other.isNegative; return result; } bigint result = subtract(other); result.isNegative = isNegative; return result; } // Subtraction operator bigint bigint::operator-(const bigint &other) const { return *this + (-other); } // Multiplication operator using optimal algorithm selection bigint bigint::operator*(const bigint &other) const { bigint result = multiply(other); result.isNegative = isNegative != other.isNegative; result.removeLeadingZeros(); return result; } // Division operator bigint bigint::operator/(const bigint &other) const { if (other.isZero()) { throw std::invalid_argument("Division by zero"); } bigint result = divide(other); result.isNegative = isNegative != other.isNegative; result.removeLeadingZeros(); return result; } // Modulo operator bigint bigint::operator%(const bigint &other) const { if (other.isZero()) { throw std::invalid_argument("Division by zero"); } bigint result = mod(other); result.isNegative = isNegative; result.removeLeadingZeros(); return result; } // Compound addition assignment bigint &bigint::operator+=(const bigint &other) { *this = *this + other; return *this; } // Compound subtraction assignment bigint &bigint::operator-=(const bigint &other) { *this = *this - other; return *this; } // Compound multiplication assignment bigint &bigint::operator*=(const bigint &other) { *this = *this * other; return *this; } // Compound division assignment bigint &bigint::operator/=(const bigint &other) { *this = *this / other; return *this; } // Compound modulo assignment bigint &bigint::operator%=(const bigint &other) { *this = *this % other; return *this; } // Equality comparison bool bigint::operator==(const bigint &other) const { return compare(other) == 0; } // Inequality comparison bool bigint::operator!=(const bigint &other) const { return compare(other) != 0; } // Less than comparison bool bigint::operator<(const bigint &other) const { return compare(other) < 0; } // Less than or equal comparison bool bigint::operator<=(const bigint &other) const { return compare(other) <= 0; } // Greater than comparison bool bigint::operator>(const bigint &other) const { return compare(other) > 0; } // Greater than or equal comparison bool bigint::operator>=(const bigint &other) const { return compare(other) >= 0; } // Convert to string representation bigint::operator std::string() const { if (isZero()) { return "0"; } std::string str; if (isNegative) { str += '-'; } // First digit without leading zeros str += std::to_string(digits[0]); // Remaining digits with leading zeros for (size_t i = 1; i < digits.size(); i++) { std::string digit = std::to_string(digits[i]); str += std::string(DIGITS_PER_ELEMENT - digit.size(), '0') + digit; } return str; } // Convert to int64_t bigint::operator int64_t() const { int64_t num = 0; for (uint32_t digit : digits) { if (num > (LLONG_MAX / static_cast<int64_t>(BASE)) || (num *= BASE) > LLONG_MAX - digit) { throw std::overflow_error("bigint too large for int64_t"); } num = num * BASE + digit; } return isNegative ? -num : num; } // Convert to boolean bigint::operator bool() const { return !isZero(); } // Absolute value bigint bigint::abs() const { bigint result = *this; result.isNegative = false; return result; } // Check if zero bool bigint::isZero() const { return digits.size() == 1 && digits[0] == 0; } // Print bigint to stdout void bigint::print() const { if (isNegative) { printf("-"); } printf("%u", digits[0]); for (size_t i = 1; i < digits.size(); i++) { printf("%09u", digits[i]); } } // Add two bigints (same sign) bigint bigint::add(const bigint &other) const { bigint result; result.digits.clear(); size_t i = digits.size(); size_t j = other.digits.size(); uint64_t carry = 0; while (i > 0 || j > 0 || carry > 0) { uint64_t sum = carry; if (i > 0) sum += digits[--i]; if (j > 0) sum += other.digits[--j]; carry = sum / BASE; result.digits.push_back(sum % BASE); } std::reverse(result.digits.begin(), result.digits.end()); result.removeLeadingZeros(); return result; } // Subtract two bigints (this > other, same sign) bigint bigint::subtract(const bigint &other) const { bigint result; result.digits.clear(); size_t i = digits.size(); size_t j = other.digits.size(); int64_t borrow = 0; while (i > 0) { int64_t diff = digits[--i] - borrow; if (j > 0) diff -= other.digits[--j]; if (diff < 0) { borrow = 1; diff += BASE; } else { borrow = 0; } result.digits.push_back(diff); } std::reverse(result.digits.begin(), result.digits.end()); result.removeLeadingZeros(); return result; } // Multiplication dispatcher bigint bigint::multiply(const bigint &other) const { // Handle simple cases if (isZero() || other.isZero()) return bigint(0); if (*this == 1) return other; if (other == 1) return *this; // Use Karatsuba for numbers larger than 10 digits if (digits.size() > 10 || other.digits.size() > 10) { return karatsuba(*this, other); } // Naive multiplication for small numbers bigint result; result.digits.resize(digits.size() + other.digits.size(), 0); for (size_t i = 0; i < digits.size(); i++) { uint64_t carry = 0; for (size_t j = 0; j < other.digits.size(); j++) { uint64_t product = static_cast<uint64_t>(digits[i]) * other.digits[j] + result.digits[i + j] + carry; carry = product / BASE; result.digits[i + j] = product % BASE; } if (carry > 0) { result.digits[i + other.digits.size()] = carry; } } result.removeLeadingZeros(); return result; } // Karatsuba multiplication (O(n^log3)) bigint bigint::karatsuba(const bigint &x, const bigint &y) const { // Base case for small numbers if (x.digits.size() < 10 || y.digits.size() < 10) { return x.multiply(y); } // Split at half the max length size_t m = std::max(x.digits.size(), y.digits.size()) / 2; // Split x and y into high and low parts bigint xHigh = x; bigint xLow; if (m < x.digits.size()) { xHigh.digits.erase(xHigh.digits.begin(), xHigh.digits.begin() + (x.digits.size() - m)); xLow.digits = std::vector<uint32_t>(x.digits.end() - m, x.digits.end()); } else { xLow = x; } bigint yHigh = y; bigint yLow; if (m < y.digits.size()) { yHigh.digits.erase(yHigh.digits.begin(), yHigh.digits.begin() + (y.digits.size() - m)); yLow.digits = std::vector<uint32_t>(y.digits.end() - m, y.digits.end()); } else { yLow = y; } // Recursive steps bigint z0 = karatsuba(xLow, yLow); bigint z1 = karatsuba((xLow + xHigh), (yLow + yHigh)); bigint z2 = karatsuba(xHigh, yHigh); // Combine results bigint temp = z1 - z2 - z0; bigint result = z2.shiftLeft(2 * m) + temp.shiftLeft(m) + z0; result.removeLeadingZeros(); return result; } // Shift left by n digits (base 10^9) bigint bigint::shiftLeft(size_t n) const { if (isZero()) { return *this; } bigint result = *this; result.digits.insert(result.digits.begin(), n, 0); return result; } // Division implementation bigint bigint::divide(const bigint &divisor) const { // Handle division by zero if (divisor.isZero()) { throw std::invalid_argument("Division by zero"); } bigint dividend = abs(); bigint div = divisor.abs(); // Special case: dividend < divisor if (dividend < div) { return bigint(0); } // Special case: divisor is single digit if (div.digits.size() == 1) { bigint quotient; quotient.digits.clear(); uint64_t carry = 0; for (size_t i = 0; i < dividend.digits.size(); i++) { uint64_t current = carry * BASE + dividend.digits[i]; quotient.digits.push_back(current / div.digits[0]); carry = current % div.digits[0]; } quotient.removeLeadingZeros(); return quotient; } // Long division for multi-digit divisor bigint quotient; bigint remainder; for (size_t i = 0; i < dividend.digits.size(); i++) { remainder = remainder.shiftLeft(1) + bigint(static_cast<int64_t>(dividend.digits[i])); if (remainder < div) { quotient.digits.push_back(0); } else { // Estimate quotient digit uint64_t q = (remainder.digits.size() > div.digits.size()) ? (static_cast<uint64_t>(remainder.digits[0]) * BASE + remainder.digits[1]) / div.digits[0] : remainder.digits[0] / div.digits[0]; q = std::min(q, BASE - 1); // Adjust quotient digit while (bigint(static_cast<int64_t>(q)) * div > remainder) { q--; } quotient.digits.push_back(q); remainder = remainder - bigint(static_cast<int64_t>(q)) * div; } } quotient.removeLeadingZeros(); return quotient; } // Modulo implementation bigint bigint::mod(const bigint &divisor) const { bigint quotient = *this / divisor; return *this - quotient * divisor; } #endif -
最近活动
- USACO 2024 December Contest Bronze复现赛不答疑 IOI
- 题目悬赏。 🧑🏫 IOI
- 「AIPI OI」 Round 6 IOI
- 不是XPCP的模拟赛(HHTOI Round 4) XCPC
- 『可达双周赛 』#18 - Div.2 IOI
- L4-1019-晋级测试四-订正 IOI
- L4-1019-晋级测试四 IOI
- L4-1019-晋级测试三-订正 IOI
- L4-1019-晋级测试三 IOI
- L4-1019-测试二-订正 IOI
- 25暑假集训 - 欧拉班 - 测试2 IOI
- L4-1019-晋级测试二 IOI
- 『可达双周赛 』#16 - Div.2 IOI
- L4-1019-晋级测试 IOI
- 25暑假集训 - 欧拉班 - 测试 IOI
- 2025可达班 第二轮选拔赛 IOI
- 『可达双周赛 』#2 - Div.2 IOI
- NOIP2024 复现赛 IOI
- 2024 CSP-J2 可达复现赛 IOI
- L3晋级测试40825-曾子乐 IOI
- CSQ-J 2024 第①轮模拟 OI
- L3晋级测试40629 -曾子乐 IOI
- 可做题杯 IOI