Skip to content

hex_big_integer_division.hpp

SECTIONMath INCLUDEnoya/hex_big_integer_division.hpp

对非负十六进制大整数求商和余数;使用 Karatsuba 与 Burnikel–Ziegler 分治除法。

\[ \displaystyle A = BQ + R,\; 0\le R < B \]

Complexity: Time: O(n^(log_2 3)) for n hexadecimal digits. Space: O(n log n).

AC 记录:division_of_hex_big_integers

跳到代码 · GitHub ↗

Implementation

当前头文件,省略 include guard;依赖见 #include

/// @complexity Time: O(n^(log_2 3)) for n hexadecimal digits.
/// Space: O(n log n).

#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstdint>
#include <iostream>
#include <string>
#include <string_view>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>

namespace noya {
namespace hex_big_integer_division_internal {

using namespace std;

struct BigInteger {
  using M = BigInteger;

  bool neg;
  vector<uint32_t> bit;
  static constexpr int log = 8;

  BigInteger() : neg(false), bit() {}

  BigInteger(bool n, const vector<uint32_t> &d) : neg(n), bit(d) {}

  BigInteger(uint32_t x) : neg(false) { bit = _integer_to_vector(x); }

  BigInteger(int32_t x) : neg(false) {
    if (x < 0)
      neg = true, x = -x;
    bit = _integer_to_vector((uint32_t)x);
  }

  template <typename I, enable_if_t<is_integral_v<I> ||
                                    is_same_v<I, __int128_t>> * = nullptr>
  BigInteger(I x) : neg(false) {
    if constexpr (is_signed_v<I> || is_same_v<I, __int128_t>) {
      if (x < 0)
        neg = true, x = -x;
    }
    bit = _integer_to_vector(x);
  }

  BigInteger(const string &S) : neg(false) {
    assert(!S.empty());
    if (S.size() == 1u && S[0] == '0')
      return;
    int l = 0;
    if (S[0] == '-')
      ++l, neg = true;

    for (int ie = S.size(); l < ie; ie -= log) {
      int is = max(l, ie - log);
      uint32_t x = 0;
      for (int i = is; i < ie; i++) {
        x <<= 4;
        if ('0' <= S[i] and S[i] <= '9') {
          x |= S[i] - '0';
        } else if ('A' <= S[i] and S[i] <= 'F') {
          x |= S[i] - 'A' + 10;
        } else if ('a' <= S[i] and S[i] <= 'f') {
          x |= S[i] - 'a' + 10;
        } else {
          assert(false);
        }
      }
      bit.push_back(x);
    }
  }

  friend M operator+(const M &lhs, const M &rhs) {
    if (lhs.neg == rhs.neg)
      return {lhs.neg, _add(lhs.bit, rhs.bit)};
    if (_leq(lhs.bit, rhs.bit)) {
      // |l| <= |r|
      auto c = _sub(rhs.bit, lhs.bit);
      bool n = _is_zero(c) ? false : rhs.neg;
      return {n, c};
    }
    auto c = _sub(lhs.bit, rhs.bit);
    bool n = _is_zero(c) ? false : lhs.neg;
    return {n, c};
  }
  friend M operator-(const M &lhs, const M &rhs) { return lhs + (-rhs); }

  friend M operator*(const M &lhs, const M &rhs) {
    auto c = _mul(lhs.bit, rhs.bit);
    bool n = _is_zero(c) ? false : (lhs.neg ^ rhs.neg);
    return {n, c};
  }
  friend pair<M, M> divmod(const M &lhs, const M &rhs) {
    auto dm = _divmod(lhs.bit, rhs.bit);
    bool dn = _is_zero(dm.first) ? false : lhs.neg != rhs.neg;
    bool mn = _is_zero(dm.second) ? false : lhs.neg;
    return {M{dn, dm.first}, M{mn, dm.second}};
  }
  friend M operator/(const M &lhs, const M &rhs) {
    return divmod(lhs, rhs).first;
  }
  friend M operator%(const M &lhs, const M &rhs) {
    return divmod(lhs, rhs).second;
  }

  M &operator+=(const M &rhs) { return (*this) = (*this) + rhs; }
  M &operator-=(const M &rhs) { return (*this) = (*this) - rhs; }
  M &operator*=(const M &rhs) { return (*this) = (*this) * rhs; }
  M &operator/=(const M &rhs) { return (*this) = (*this) / rhs; }
  M &operator%=(const M &rhs) { return (*this) = (*this) % rhs; }

  M operator-() const {
    if (is_zero())
      return *this;
    return {!neg, bit};
  }
  M operator+() const { return *this; }
  friend M abs(const M &m) { return {false, m.bit}; }
  bool is_zero() const { return _is_zero(bit); }

  friend bool operator==(const M &lhs, const M &rhs) {
    return lhs.neg == rhs.neg && lhs.bit == rhs.bit;
  }
  friend bool operator!=(const M &lhs, const M &rhs) {
    return lhs.neg != rhs.neg || lhs.bit != rhs.bit;
  }
  friend bool operator<(const M &lhs, const M &rhs) {
    if (lhs == rhs)
      return false;
    return _neq_lt(lhs, rhs);
  }
  friend bool operator<=(const M &lhs, const M &rhs) {
    if (lhs == rhs)
      return true;
    return _neq_lt(lhs, rhs);
  }
  friend bool operator>(const M &lhs, const M &rhs) {
    if (lhs == rhs)
      return false;
    return _neq_lt(rhs, lhs);
  }
  friend bool operator>=(const M &lhs, const M &rhs) {
    if (lhs == rhs)
      return true;
    return _neq_lt(rhs, lhs);
  }

  string to_string() const {
    if (is_zero())
      return "0";
    string res;
    if (neg)
      res.push_back('-');
    for (int i = _size() - 1; i >= 0; i--) {
      res += _itos(bit[i], i != _size() - 1);
    }
    return res;
  }

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

  friend ostream &operator<<(ostream &os, const M &m) {
    return os << m.to_string();
  }

private:
  // size
  int _size() const { return bit.size(); }
  // a == b
  static bool _eq(const vector<uint32_t> &a, const vector<uint32_t> &b) {
    return a == b;
  }
  // a < b
  static bool _lt(const vector<uint32_t> &a, const vector<uint32_t> &b) {
    return _lt(a.cbegin(), a.cend(), b.cbegin(), b.cend());
  }
  // a <= b
  static bool _leq(const vector<uint32_t> &a, const vector<uint32_t> &b) {
    return _eq(a, b) || _lt(a, b);
  }
  // a < b (s.t. a != b)
  static bool _neq_lt(const M &lhs, const M &rhs) {
    assert(lhs != rhs);
    if (lhs.neg != rhs.neg)
      return lhs.neg;
    bool f = _lt(lhs.bit, rhs.bit);
    if (f)
      return !lhs.neg;
    return lhs.neg;
  }
  // a == 0
  static bool _is_zero(const vector<uint32_t> &a) { return a.empty(); }
  // a == 1
  static bool _is_one(const vector<uint32_t> &a) {
    return (int)a.size() == 1 && a[0] == 1;
  }
  // 末尾 0 を削除
  static void _shrink(vector<uint32_t> &a) {
    while (a.size() && a.back() == 0)
      a.pop_back();
  }
  // 末尾 0 を削除
  void _shrink() {
    while (_size() && bit.back() == 0)
      bit.pop_back();
  }
  // a + b
  static vector<uint32_t> _add(const vector<uint32_t> &a,
                               const vector<uint32_t> &b) {
    vector<uint32_t> c(max<int>(a.size(), b.size()) + 1);
    _add(a.cbegin(), a.cend(), b.cbegin(), b.cend(), c.begin(), c.end());
    _shrink(c);
    return c;
  }
  // a - b
  static vector<uint32_t> _sub(const vector<uint32_t> &a,
                               const vector<uint32_t> &b) {
    assert(_leq(b, a));
    vector<uint32_t> c{a};
    _sub(c.begin(), c.end(), b.cbegin(), b.cend());
    _shrink(c);
    return c;
  }

  // a * b
  static vector<uint32_t> _mul(const vector<uint32_t> &a,
                               const vector<uint32_t> &b) {
    if (_is_zero(a) || _is_zero(b))
      return {};
    if (_is_one(a))
      return b;
    if (_is_one(b))
      return a;

    vector<uint32_t> c(a.size() + b.size());
    _mul(a.cbegin(), a.cend(), b.cbegin(), b.cend(), c.begin(), c.end());
    _shrink(c);
    return c;
  }

  // a / b
  static pair<vector<uint32_t>, vector<uint32_t>>
  _divmod(const vector<uint32_t> &a, const vector<uint32_t> &b) {
    if (_is_zero(b)) {
      cerr << "Divide by Zero Exception" << endl;
      exit(1);
    }

    if (a.size() < b.size()) {
      return {{}, a};
    }

    vector<uint32_t> q(a.size() - b.size() + 1);
    vector<uint32_t> r(b.size());

    _divmod(a.cbegin(), a.cend(), b.cbegin(), b.cend(), q.begin(), q.end(),
            r.begin(), r.end());
    _shrink(q);
    _shrink(r);
    return {q, r};
  }

  using iter = typename vector<uint32_t>::iterator;
  using citer = typename vector<uint32_t>::const_iterator;

  // a + b
  static void _add(citer a, citer ae, citer b, citer be, iter c, iter ce) {
    if (ae - a < be - b) {
      swap(a, b);
      swap(ae, be);
    }
    const size_t asi = ae - a;
    const size_t bsi = be - b;
    const size_t csi = ce - c;
    assert(asi <= csi);

    uint32_t car = 0;
    for (size_t i = 0; i < bsi; i++) {
      uint64_t v = (uint64_t)a[i] + b[i] + car;
      c[i] = (uint32_t)v;
      car = v >> 32;
    }
    for (size_t i = bsi; i < asi; i++) {
      uint64_t v = (uint64_t)a[i] + car;
      c[i] = (uint32_t)v;
      car = v >> 32;
    }
    if (car != 0) {
      assert(c + asi < ce);
      c[asi] = car;
    }
  }

  // a += b
  static void _add(iter a, iter ae, citer b, citer be) {
    const size_t asi = ae - a;
    const size_t bsi = be - b;

    uint32_t car = 0;
    for (size_t i = 0; i < bsi; i++) {
      uint64_t v = (uint64_t)a[i] + b[i] + car;
      a[i] = (uint32_t)v;
      car = v >> 32;
    }
    for (size_t i = bsi; car != 0 && i < asi; i++) {
      uint64_t v = (uint64_t)a[i] + car;
      a[i] = (uint32_t)v;
      car = v >> 32;
    }
  }
  // a -= b
  static void _sub(iter a, iter ae, citer b, citer be) {
    const size_t asi = ae - a;
    const size_t bsi = be - b;

    int32_t car = 0;
    for (size_t i = 0; i < bsi; i++) {
      int64_t v = (int64_t)a[i] - b[i] + car;
      a[i] = v;
      car = v >> 32;
    }
    for (size_t i = bsi; car != 0 && i < asi; i++) {
      int64_t v = (int64_t)a[i] + car;
      a[i] = v;
      car = v >> 32;
    }
    assert(car == 0);
  }

  // a * b
  static void _mul(citer a, citer ae, citer b, citer be, iter c, iter ce) {
    if (ae - a < be - b) {
      swap(a, b);
      swap(ae, be);
    }
    const size_t asi = ae - a;
    const size_t bsi = be - b;
    const size_t csi = ce - c;
    assert(csi == asi + bsi);

    if (bsi <= 128) {
      _mul_naive(a, ae, b, be, c, ce);
      return;
    }
    // Karatsuba reduces four half-size products to three.
    // |  A_hi  |  A_lo  |
    // |  B_hi  |  B_lo  |

    // z0 := A_lo * B_lo
    // z2 := A_hi * B_hi
    // z1 := A_hi * B_lo + A_lo * B_hi

    // z1 = (A_hi+A_lo) * (B_hi+B_lo) - z0 - z2

    // A * B = (z2<<(2*shf)) + (z1<<shf) + z0

    const size_t n = (asi + 1) >> 1;
    if (bsi <= n) {
      // |  A_hi  |  A_lo  |
      // |   0    |   B    |

      // A_lo * B
      _mul(a, a + n, b, be, c, c + n + bsi);

      vector<uint32_t> car(c + n, c + n + bsi);
      fill(c + n, c + n + bsi, 0);

      // A_hi * B
      _mul(a + n, ae, b, be, c + n, ce);

      _add(c + n, ce, car.cbegin(), car.cend());
    } else {
      // A_lo * B_lo
      _mul(a, a + n, b, b + n, c, c + n + n);

      // A_hi * B_hi
      _mul(a + n, ae, b + n, be, c + n + n, ce);

      vector<uint32_t> a1(n + 1);
      vector<uint32_t> b1(n + 1);
      vector<uint32_t> z1(2 * n + 2);
      _add(a, a + n, a + n, ae, a1.begin(), a1.end());
      _add(b, b + n, b + n, be, b1.begin(), b1.end());
      _mul(a1.cbegin(), a1.cend(), b1.cbegin(), b1.cend(), z1.begin(),
           z1.end());

      _sub(z1.begin(), z1.end(), c, c + n + n);
      _sub(z1.begin(), z1.end(), c + n + n, ce);

      _shrink(z1);
      _add(c + n, ce, z1.begin(), z1.end());
    }
  }

  // a * b (naive)
  static void _mul_naive(citer a, citer ae, citer b, citer be, iter c,
                         iter ce) {
    const size_t asi = ae - a;
    const size_t bsi = be - b;
    const size_t csi = ce - c;
    if (asi == 0 || bsi == 0)
      return;
    assert(csi == asi + bsi);

    for (size_t i = 0; i < asi; i++) {
      uint32_t car = 0;
      for (size_t j = 0; j < bsi; j++) {
        uint64_t p = 1LL * a[i] * b[j] + car + c[i + j];
        c[i + j] = p;
        car = p >> 32;
      }
      c[i + bsi] = car;
    }
  }

  static const int DNT = 64;

  // a / b
  static void _divmod(citer a, citer ae, citer b, citer be, iter quo, iter qe,
                      iter rem, iter re) {
    const size_t asi = ae - a;
    const size_t bsi = be - b;
    const size_t qsi = qe - quo;
    const size_t rsi = re - rem;

    assert(bsi > 0);
    assert(qsi == asi - bsi + 1);
    assert(rsi == bsi);

    if (min(asi - bsi, bsi) <= DNT) {
      _divmod_naive(a, ae, b, be, quo, qe, rem, re);
      return;
    }

    // Round the divisor length to balanced blocks before recursive division.

    size_t n;
    {
      size_t m = (bsi + DNT - 1) / DNT;
      if (m > 1)
        m = 1 << (32 - __builtin_clz(m - 1));

      size_t j = (bsi + m - 1) / m;
      n = j * m;
    }

    const int sd = n - bsi;
    const int ss = __builtin_clz(*(be - 1));

    vector<uint32_t> x(asi + sd + (__builtin_clz(*(ae - 1)) <= ss ? 1 : 0));
    vector<uint32_t> y(n);
    vector<uint32_t> r(n + 1);
    vector<uint32_t> z(2 * n);

    copy(a, ae, x.begin() + sd);
    copy(b, be, y.begin() + sd);

    _left_shift(x.begin() + sd, x.end(), ss);
    _left_shift(y.begin() + sd, y.end(), ss);

    size_t t = max<size_t>(2, (x.size() + n - 1) / n);
    copy(x.cbegin() + (t - 2) * n, x.cend(), z.begin());

    const size_t ql = qe - (quo + (t - 2) * n);
    if (ql < n) {
      vector<uint32_t> qq(n);
      _divmod_d2n1n(z.begin(), z.end(), y.begin(), y.end(), qq.begin(),
                    qq.end(), r.begin(), r.end());
      copy(qq.cbegin(), qq.cbegin() + ql, quo + (t - 2) * n);
    } else {
      _divmod_d2n1n(z.begin(), z.end(), y.begin(), y.end(), quo + (t - 2) * n,
                    quo + (t - 1) * n, r.begin(), r.end());
    }

    for (int i = t - 3; i >= 0; --i) {
      copy(x.begin() + i * n, x.begin() + (i + 1) * n, z.begin());
      copy(r.begin(), r.begin() + n, z.begin() + n);
      fill(r.begin(), r.end(), 0);

      _divmod_d2n1n(z.begin(), z.end(), y.begin(), y.end(), quo + i * n,
                    quo + (i + 1) * n, r.begin(), r.end());
    }

    _shrink(r);
    copy(r.cbegin() + sd, r.cbegin() + sd + rsi, rem);
    _right_shift(rem, re, ss);
  }

  // a(2n bits) / b(n bits)
  static void _divmod_d2n1n(citer a, citer ae, citer b, citer be, iter quo,
                            iter qe, iter rem, iter re) {
    const size_t asi = ae - a;
    const size_t bsi = be - b;
    const size_t qsi = qe - quo;
    const size_t rsi = re - rem;
    const size_t n = bsi;

    assert(asi == 2 * n);
    assert(qsi == n);
    assert(rsi == n + 1);
    assert(_lt(a + n, ae, b, be));

    if (n % 2 != 0 || n <= DNT) {
      _divmod_naive(a, ae, b, be, quo, qe, rem, re);
      return;
    }
    const size_t hal = n >> 1;
    vector<uint32_t> r1(n + hal + 1);
    copy(a, a + hal, r1.begin());

    _divmod_d3n2n(a + hal, ae, b, be, quo + hal, qe, r1.begin() + hal,
                  r1.end());
    _divmod_d3n2n(r1.cbegin(), r1.cend() - 1, b, be, quo, quo + hal, rem, re);
  }

  // a(3n bits) / b(2n bits)
  static void _divmod_d3n2n(citer a, citer ae, citer b, citer be, iter quo,
                            iter qe, iter rem, iter re) {
    const size_t asi = ae - a;
    const size_t bsi = be - b;
    const size_t qsi = qe - quo;
    const size_t rsi = re - rem;
    const size_t n = bsi >> 1;

    assert(asi == 3 * n);
    assert(bsi == 2 * n);
    assert(qsi == n);
    assert(rsi == 2 * n + 1);
    assert(_lt(a + n, ae, b, be));

    vector<uint32_t> d(2 * n);

    if (_lt(a + n + n, ae, b + n, be)) {
      _divmod_d2n1n(a + n, ae, b + n, be, quo, qe, rem + n, re);
      _mul(quo, qe, b, b + n, d.begin(), d.end());
    } else {
      fill(quo, qe, UINT32_MAX);

      _add(a + n, a + n + n, b + n, be, rem + n, re);
      copy(b, b + n, d.begin() + n);
      _sub(d.begin(), d.end(), b, b + n);
    }

    copy(a, a + n, rem);

    while (_lt(rem, re, d.cbegin(), d.cend())) {
      _add(rem, re, b, be);
      vector<uint32_t> one{1};
      _sub(quo, qe, one.cbegin(), one.cend());
    }
    _sub(rem, re, d.cbegin(), d.cend());
  }

  // a / b (naive)
  static void _divmod_naive(citer a, citer ae, citer b, citer be, iter quo,
                            iter qe, iter rem, iter re) {
    const size_t asi = ae - a;
    const size_t bsi = be - b;
    if (bsi == 0) {
      cerr << "Divide by Zero Exception" << endl;
      exit(1);
    }

    if (bsi == 1) {
      uint64_t car = 0;
      for (size_t i = asi - 1; 0 <= (int)i; --i) {
        uint64_t v = (car << 32) | a[i];
        quo[i] = v / (*b);
        car = v - quo[i] * (*b);
      }
      *rem = (uint32_t)car;
      return;
    }
    if (max(asi, bsi) <= 2) {
      uint64_t a64 = _iter_to_integer<uint64_t>(a, ae),
               b64 = _iter_to_integer<uint64_t>(b, be);
      _integer_to_iter(a64 / b64, quo, qe);
      _integer_to_iter(a64 % b64, rem, re);
      return;
    }
    if (_lt(a, ae, b, be)) {
      if (asi > bsi)
        ae = a + bsi;
      copy(a, ae, rem);
      return;
    }
    // B > 0xFFFFFFFF, A >= B

    // 割る数のビットを大きくする
    const int shf = __builtin_clz(*(be - 1));
    vector<uint32_t> x(asi + (__builtin_clz(*(ae - 1)) < shf ? 1 : 0));
    copy(a, ae, x.begin());
    vector<uint32_t> y(b, be);

    _left_shift(x.begin(), x.end(), shf);
    _left_shift(y.begin(), y.end(), shf);

    uint32_t yb = y.back();
    vector<uint32_t> qv(x.size() - y.size() + 1);
    vector<uint32_t> rv(x.end() - y.size(), x.end());
    for (int i = qv.size() - 1; i >= 0; i--) {
      if (rv.size() < y.size()) {
        // do nothing
      } else if (rv.size() == y.size()) {
        if (_leq(y, rv)) {
          qv[i] = 1, rv = _sub(rv, y);
        }
      } else {
        assert(y.size() + 1 == rv.size());
        uint64_t rb = rv[rv.size() - 1];
        rb <<= 32;
        rb |= rv[rv.size() - 2];
        uint64_t q = rb / yb;
        if (q > UINT32_MAX)
          q = UINT32_MAX;

        vector<uint32_t> yq = _mul(y, {(uint32_t)q});
        // 真の商は q-2 以上 q+1 以下だが自信が無いので念のため while を回す
        while (_lt(rv, yq))
          q--, yq = _sub(yq, y);
        rv = _sub(rv, yq);
        while (_leq(y, rv))
          q++, rv = _sub(rv, y);
        qv[i] = q;
      }
      if (i)
        rv.insert(begin(rv), x[i - 1]);
      _shrink(rv);
    }

    _shrink(qv);
    _right_shift(rv.begin(), rv.end(), shf);
    _shrink(rv);

    copy(qv.cbegin(), qv.cend(), quo);
    copy(rv.cbegin(), rv.cend(), rem);
  }

  // int -> string
  // 先頭かどうかに応じて zero padding するかを決める
  static string _itos(uint32_t x, bool pad) {
    string res;
    for (int i = 0; i < log; i++) {
      uint32_t d = x % 16;
      if (d < 10)
        res.push_back('0' + d);
      else if (d < 16)
        res.push_back('A' + d - 10);
      else
        assert(false);
      x /= 16;
    }
    if (!pad) {
      while (res.size() && res.back() == '0')
        res.pop_back();
      assert(!res.empty());
    }
    reverse(begin(res), end(res));
    return res;
  }

  template <typename I, enable_if_t<is_integral_v<I> ||
                                    is_same_v<I, __int128_t>> * = nullptr>
  static I _iter_to_integer(citer it, const citer end) {
    I res = 0;
    int shf = 0;
    while (it != end) {
      res |= (I)*it << shf;
      shf += 32;
      ++it;
    }
    return res;
  }

  template <typename I, enable_if_t<is_integral_v<I> ||
                                    is_same_v<I, __int128_t>> * = nullptr>
  static void _integer_to_iter(I x, iter it, const iter end) {
    if constexpr (is_signed_v<I> || is_same_v<I, __int128_t>) {
      assert(x >= 0);
    }
    while (x) {
      assert(it < end);
      *it = (uint32_t)x;
      ++it;
      x >>= 32;
    }
  }

  static vector<uint32_t> _integer_to_vector(uint32_t x) {
    return vector<uint32_t>{x};
  }

  template <typename I, enable_if_t<is_integral_v<I> ||
                                    is_same_v<I, __int128_t>> * = nullptr>
  static vector<uint32_t> _integer_to_vector(I x) {
    if constexpr (is_signed_v<I> || is_same_v<I, __int128_t>) {
      assert(x >= 0);
    }
    vector<uint32_t> rt;
    while (x) {
      rt.push_back((uint32_t)x);
      x >>= 32;
    }
    return rt;
  }

  // a << shf
  static void _left_shift(const iter a, const iter ae, int shf) {
    assert(shf < 32);
    if (shf == 0)
      return;
    const int bac = 32 - shf;
    uint32_t car = 0;
    for (iter it = a; it < ae; ++it) {
      uint32_t v = (*it << shf) | car;
      car = *it >> bac;
      *it = v;
    }
    assert(car == 0);
  }
  // a >> shf
  static void _right_shift(const iter a, const iter ae, int shf) {
    assert(shf < 32);
    if (shf == 0)
      return;
    const int bac = 32 - shf;
    uint32_t car = 0;
    for (iter it = ae - 1; a <= it; --it) {
      uint32_t v = (*it >> shf) | car;
      car = *it << bac;
      *it = v;
    }
    assert(car == 0);
  }

  // a < b
  static bool _lt(citer a, citer ae, citer b, citer be) {
    size_t asi = ae - a;
    size_t bsi = be - b;

    if (asi != bsi) {
      if (asi < bsi) {
        auto nz = std::find_if(b + asi, be, [](uint32_t x) { return x != 0; });
        if (nz != be)
          return true;

        be = b + asi;
        bsi = asi;
      } else {
        auto nz = std::find_if(a + bsi, ae, [](uint32_t x) { return x != 0; });
        if (nz != ae)
          return false;
        ae = a + bsi;
        asi = bsi;
      }
    }
    for (int i = asi - 1; i >= 0; i--) {
      if (a[i] != b[i])
        return a[i] < b[i];
    }
    return false;
  }

  static void _dump(const vector<uint32_t> &a, string s = "") {
    _dump(a.cbegin(), a.cend(), s);
  }

  static void _dump(citer a, citer ae, string s = "") {
    if (!s.empty())
      cerr << s << " : ";
    cerr << "{ ";
    for (citer it = a; it < ae; ++it) {
      cerr << *it << ", ";
    }
    cerr << "}" << endl;
  }
};

using bigint = BigInteger;

} // namespace hex_big_integer_division_internal

/// @brief Divide nonnegative hexadecimal integers stored in 32-bit limbs.
/// Karatsuba supplies subquadratic multiplication, while Burnikel-Ziegler
/// splits a normalized 2n-by-n division into balanced 3n/2-by-n and
/// n-by-n/2 subproblems; short blocks fall back to Knuth-style long division.
inline std::pair<std::string, std::string>
divide_hex_big_integers(std::string_view div, std::string_view dvs) {
  using hex_big_integer_division_internal::bigint;
  bigint fir{std::string(div)};
  bigint sec{std::string(dvs)};
  auto [qtn, rmn] = divmod(fir, sec);
  return {qtn.to_string(), rmn.to_string()};
}

} // namespace noya
#ifndef NOYA_HEX_BIG_INTEGER_DIVISION_HPP
#define NOYA_HEX_BIG_INTEGER_DIVISION_HPP 1

/// @complexity Time: O(n^(log_2 3)) for n hexadecimal digits.
/// Space: O(n log n).

#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstdint>
#include <iostream>
#include <string>
#include <string_view>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>

namespace noya {
namespace hex_big_integer_division_internal {

using namespace std;

struct BigInteger {
  using M = BigInteger;

  bool neg;
  vector<uint32_t> bit;
  static constexpr int log = 8;

  BigInteger() : neg(false), bit() {}

  BigInteger(bool n, const vector<uint32_t> &d) : neg(n), bit(d) {}

  BigInteger(uint32_t x) : neg(false) { bit = _integer_to_vector(x); }

  BigInteger(int32_t x) : neg(false) {
    if (x < 0)
      neg = true, x = -x;
    bit = _integer_to_vector((uint32_t)x);
  }

  template <typename I, enable_if_t<is_integral_v<I> ||
                                    is_same_v<I, __int128_t>> * = nullptr>
  BigInteger(I x) : neg(false) {
    if constexpr (is_signed_v<I> || is_same_v<I, __int128_t>) {
      if (x < 0)
        neg = true, x = -x;
    }
    bit = _integer_to_vector(x);
  }

  BigInteger(const string &S) : neg(false) {
    assert(!S.empty());
    if (S.size() == 1u && S[0] == '0')
      return;
    int l = 0;
    if (S[0] == '-')
      ++l, neg = true;

    for (int ie = S.size(); l < ie; ie -= log) {
      int is = max(l, ie - log);
      uint32_t x = 0;
      for (int i = is; i < ie; i++) {
        x <<= 4;
        if ('0' <= S[i] and S[i] <= '9') {
          x |= S[i] - '0';
        } else if ('A' <= S[i] and S[i] <= 'F') {
          x |= S[i] - 'A' + 10;
        } else if ('a' <= S[i] and S[i] <= 'f') {
          x |= S[i] - 'a' + 10;
        } else {
          assert(false);
        }
      }
      bit.push_back(x);
    }
  }

  friend M operator+(const M &lhs, const M &rhs) {
    if (lhs.neg == rhs.neg)
      return {lhs.neg, _add(lhs.bit, rhs.bit)};
    if (_leq(lhs.bit, rhs.bit)) {
      // |l| <= |r|
      auto c = _sub(rhs.bit, lhs.bit);
      bool n = _is_zero(c) ? false : rhs.neg;
      return {n, c};
    }
    auto c = _sub(lhs.bit, rhs.bit);
    bool n = _is_zero(c) ? false : lhs.neg;
    return {n, c};
  }
  friend M operator-(const M &lhs, const M &rhs) { return lhs + (-rhs); }

  friend M operator*(const M &lhs, const M &rhs) {
    auto c = _mul(lhs.bit, rhs.bit);
    bool n = _is_zero(c) ? false : (lhs.neg ^ rhs.neg);
    return {n, c};
  }
  friend pair<M, M> divmod(const M &lhs, const M &rhs) {
    auto dm = _divmod(lhs.bit, rhs.bit);
    bool dn = _is_zero(dm.first) ? false : lhs.neg != rhs.neg;
    bool mn = _is_zero(dm.second) ? false : lhs.neg;
    return {M{dn, dm.first}, M{mn, dm.second}};
  }
  friend M operator/(const M &lhs, const M &rhs) {
    return divmod(lhs, rhs).first;
  }
  friend M operator%(const M &lhs, const M &rhs) {
    return divmod(lhs, rhs).second;
  }

  M &operator+=(const M &rhs) { return (*this) = (*this) + rhs; }
  M &operator-=(const M &rhs) { return (*this) = (*this) - rhs; }
  M &operator*=(const M &rhs) { return (*this) = (*this) * rhs; }
  M &operator/=(const M &rhs) { return (*this) = (*this) / rhs; }
  M &operator%=(const M &rhs) { return (*this) = (*this) % rhs; }

  M operator-() const {
    if (is_zero())
      return *this;
    return {!neg, bit};
  }
  M operator+() const { return *this; }
  friend M abs(const M &m) { return {false, m.bit}; }
  bool is_zero() const { return _is_zero(bit); }

  friend bool operator==(const M &lhs, const M &rhs) {
    return lhs.neg == rhs.neg && lhs.bit == rhs.bit;
  }
  friend bool operator!=(const M &lhs, const M &rhs) {
    return lhs.neg != rhs.neg || lhs.bit != rhs.bit;
  }
  friend bool operator<(const M &lhs, const M &rhs) {
    if (lhs == rhs)
      return false;
    return _neq_lt(lhs, rhs);
  }
  friend bool operator<=(const M &lhs, const M &rhs) {
    if (lhs == rhs)
      return true;
    return _neq_lt(lhs, rhs);
  }
  friend bool operator>(const M &lhs, const M &rhs) {
    if (lhs == rhs)
      return false;
    return _neq_lt(rhs, lhs);
  }
  friend bool operator>=(const M &lhs, const M &rhs) {
    if (lhs == rhs)
      return true;
    return _neq_lt(rhs, lhs);
  }

  string to_string() const {
    if (is_zero())
      return "0";
    string res;
    if (neg)
      res.push_back('-');
    for (int i = _size() - 1; i >= 0; i--) {
      res += _itos(bit[i], i != _size() - 1);
    }
    return res;
  }

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

  friend ostream &operator<<(ostream &os, const M &m) {
    return os << m.to_string();
  }

private:
  // size
  int _size() const { return bit.size(); }
  // a == b
  static bool _eq(const vector<uint32_t> &a, const vector<uint32_t> &b) {
    return a == b;
  }
  // a < b
  static bool _lt(const vector<uint32_t> &a, const vector<uint32_t> &b) {
    return _lt(a.cbegin(), a.cend(), b.cbegin(), b.cend());
  }
  // a <= b
  static bool _leq(const vector<uint32_t> &a, const vector<uint32_t> &b) {
    return _eq(a, b) || _lt(a, b);
  }
  // a < b (s.t. a != b)
  static bool _neq_lt(const M &lhs, const M &rhs) {
    assert(lhs != rhs);
    if (lhs.neg != rhs.neg)
      return lhs.neg;
    bool f = _lt(lhs.bit, rhs.bit);
    if (f)
      return !lhs.neg;
    return lhs.neg;
  }
  // a == 0
  static bool _is_zero(const vector<uint32_t> &a) { return a.empty(); }
  // a == 1
  static bool _is_one(const vector<uint32_t> &a) {
    return (int)a.size() == 1 && a[0] == 1;
  }
  // 末尾 0 を削除
  static void _shrink(vector<uint32_t> &a) {
    while (a.size() && a.back() == 0)
      a.pop_back();
  }
  // 末尾 0 を削除
  void _shrink() {
    while (_size() && bit.back() == 0)
      bit.pop_back();
  }
  // a + b
  static vector<uint32_t> _add(const vector<uint32_t> &a,
                               const vector<uint32_t> &b) {
    vector<uint32_t> c(max<int>(a.size(), b.size()) + 1);
    _add(a.cbegin(), a.cend(), b.cbegin(), b.cend(), c.begin(), c.end());
    _shrink(c);
    return c;
  }
  // a - b
  static vector<uint32_t> _sub(const vector<uint32_t> &a,
                               const vector<uint32_t> &b) {
    assert(_leq(b, a));
    vector<uint32_t> c{a};
    _sub(c.begin(), c.end(), b.cbegin(), b.cend());
    _shrink(c);
    return c;
  }

  // a * b
  static vector<uint32_t> _mul(const vector<uint32_t> &a,
                               const vector<uint32_t> &b) {
    if (_is_zero(a) || _is_zero(b))
      return {};
    if (_is_one(a))
      return b;
    if (_is_one(b))
      return a;

    vector<uint32_t> c(a.size() + b.size());
    _mul(a.cbegin(), a.cend(), b.cbegin(), b.cend(), c.begin(), c.end());
    _shrink(c);
    return c;
  }

  // a / b
  static pair<vector<uint32_t>, vector<uint32_t>>
  _divmod(const vector<uint32_t> &a, const vector<uint32_t> &b) {
    if (_is_zero(b)) {
      cerr << "Divide by Zero Exception" << endl;
      exit(1);
    }

    if (a.size() < b.size()) {
      return {{}, a};
    }

    vector<uint32_t> q(a.size() - b.size() + 1);
    vector<uint32_t> r(b.size());

    _divmod(a.cbegin(), a.cend(), b.cbegin(), b.cend(), q.begin(), q.end(),
            r.begin(), r.end());
    _shrink(q);
    _shrink(r);
    return {q, r};
  }

  using iter = typename vector<uint32_t>::iterator;
  using citer = typename vector<uint32_t>::const_iterator;

  // a + b
  static void _add(citer a, citer ae, citer b, citer be, iter c, iter ce) {
    if (ae - a < be - b) {
      swap(a, b);
      swap(ae, be);
    }
    const size_t asi = ae - a;
    const size_t bsi = be - b;
    const size_t csi = ce - c;
    assert(asi <= csi);

    uint32_t car = 0;
    for (size_t i = 0; i < bsi; i++) {
      uint64_t v = (uint64_t)a[i] + b[i] + car;
      c[i] = (uint32_t)v;
      car = v >> 32;
    }
    for (size_t i = bsi; i < asi; i++) {
      uint64_t v = (uint64_t)a[i] + car;
      c[i] = (uint32_t)v;
      car = v >> 32;
    }
    if (car != 0) {
      assert(c + asi < ce);
      c[asi] = car;
    }
  }

  // a += b
  static void _add(iter a, iter ae, citer b, citer be) {
    const size_t asi = ae - a;
    const size_t bsi = be - b;

    uint32_t car = 0;
    for (size_t i = 0; i < bsi; i++) {
      uint64_t v = (uint64_t)a[i] + b[i] + car;
      a[i] = (uint32_t)v;
      car = v >> 32;
    }
    for (size_t i = bsi; car != 0 && i < asi; i++) {
      uint64_t v = (uint64_t)a[i] + car;
      a[i] = (uint32_t)v;
      car = v >> 32;
    }
  }
  // a -= b
  static void _sub(iter a, iter ae, citer b, citer be) {
    const size_t asi = ae - a;
    const size_t bsi = be - b;

    int32_t car = 0;
    for (size_t i = 0; i < bsi; i++) {
      int64_t v = (int64_t)a[i] - b[i] + car;
      a[i] = v;
      car = v >> 32;
    }
    for (size_t i = bsi; car != 0 && i < asi; i++) {
      int64_t v = (int64_t)a[i] + car;
      a[i] = v;
      car = v >> 32;
    }
    assert(car == 0);
  }

  // a * b
  static void _mul(citer a, citer ae, citer b, citer be, iter c, iter ce) {
    if (ae - a < be - b) {
      swap(a, b);
      swap(ae, be);
    }
    const size_t asi = ae - a;
    const size_t bsi = be - b;
    const size_t csi = ce - c;
    assert(csi == asi + bsi);

    if (bsi <= 128) {
      _mul_naive(a, ae, b, be, c, ce);
      return;
    }
    // Karatsuba reduces four half-size products to three.
    // |  A_hi  |  A_lo  |
    // |  B_hi  |  B_lo  |

    // z0 := A_lo * B_lo
    // z2 := A_hi * B_hi
    // z1 := A_hi * B_lo + A_lo * B_hi

    // z1 = (A_hi+A_lo) * (B_hi+B_lo) - z0 - z2

    // A * B = (z2<<(2*shf)) + (z1<<shf) + z0

    const size_t n = (asi + 1) >> 1;
    if (bsi <= n) {
      // |  A_hi  |  A_lo  |
      // |   0    |   B    |

      // A_lo * B
      _mul(a, a + n, b, be, c, c + n + bsi);

      vector<uint32_t> car(c + n, c + n + bsi);
      fill(c + n, c + n + bsi, 0);

      // A_hi * B
      _mul(a + n, ae, b, be, c + n, ce);

      _add(c + n, ce, car.cbegin(), car.cend());
    } else {
      // A_lo * B_lo
      _mul(a, a + n, b, b + n, c, c + n + n);

      // A_hi * B_hi
      _mul(a + n, ae, b + n, be, c + n + n, ce);

      vector<uint32_t> a1(n + 1);
      vector<uint32_t> b1(n + 1);
      vector<uint32_t> z1(2 * n + 2);
      _add(a, a + n, a + n, ae, a1.begin(), a1.end());
      _add(b, b + n, b + n, be, b1.begin(), b1.end());
      _mul(a1.cbegin(), a1.cend(), b1.cbegin(), b1.cend(), z1.begin(),
           z1.end());

      _sub(z1.begin(), z1.end(), c, c + n + n);
      _sub(z1.begin(), z1.end(), c + n + n, ce);

      _shrink(z1);
      _add(c + n, ce, z1.begin(), z1.end());
    }
  }

  // a * b (naive)
  static void _mul_naive(citer a, citer ae, citer b, citer be, iter c,
                         iter ce) {
    const size_t asi = ae - a;
    const size_t bsi = be - b;
    const size_t csi = ce - c;
    if (asi == 0 || bsi == 0)
      return;
    assert(csi == asi + bsi);

    for (size_t i = 0; i < asi; i++) {
      uint32_t car = 0;
      for (size_t j = 0; j < bsi; j++) {
        uint64_t p = 1LL * a[i] * b[j] + car + c[i + j];
        c[i + j] = p;
        car = p >> 32;
      }
      c[i + bsi] = car;
    }
  }

  static const int DNT = 64;

  // a / b
  static void _divmod(citer a, citer ae, citer b, citer be, iter quo, iter qe,
                      iter rem, iter re) {
    const size_t asi = ae - a;
    const size_t bsi = be - b;
    const size_t qsi = qe - quo;
    const size_t rsi = re - rem;

    assert(bsi > 0);
    assert(qsi == asi - bsi + 1);
    assert(rsi == bsi);

    if (min(asi - bsi, bsi) <= DNT) {
      _divmod_naive(a, ae, b, be, quo, qe, rem, re);
      return;
    }

    // Round the divisor length to balanced blocks before recursive division.

    size_t n;
    {
      size_t m = (bsi + DNT - 1) / DNT;
      if (m > 1)
        m = 1 << (32 - __builtin_clz(m - 1));

      size_t j = (bsi + m - 1) / m;
      n = j * m;
    }

    const int sd = n - bsi;
    const int ss = __builtin_clz(*(be - 1));

    vector<uint32_t> x(asi + sd + (__builtin_clz(*(ae - 1)) <= ss ? 1 : 0));
    vector<uint32_t> y(n);
    vector<uint32_t> r(n + 1);
    vector<uint32_t> z(2 * n);

    copy(a, ae, x.begin() + sd);
    copy(b, be, y.begin() + sd);

    _left_shift(x.begin() + sd, x.end(), ss);
    _left_shift(y.begin() + sd, y.end(), ss);

    size_t t = max<size_t>(2, (x.size() + n - 1) / n);
    copy(x.cbegin() + (t - 2) * n, x.cend(), z.begin());

    const size_t ql = qe - (quo + (t - 2) * n);
    if (ql < n) {
      vector<uint32_t> qq(n);
      _divmod_d2n1n(z.begin(), z.end(), y.begin(), y.end(), qq.begin(),
                    qq.end(), r.begin(), r.end());
      copy(qq.cbegin(), qq.cbegin() + ql, quo + (t - 2) * n);
    } else {
      _divmod_d2n1n(z.begin(), z.end(), y.begin(), y.end(), quo + (t - 2) * n,
                    quo + (t - 1) * n, r.begin(), r.end());
    }

    for (int i = t - 3; i >= 0; --i) {
      copy(x.begin() + i * n, x.begin() + (i + 1) * n, z.begin());
      copy(r.begin(), r.begin() + n, z.begin() + n);
      fill(r.begin(), r.end(), 0);

      _divmod_d2n1n(z.begin(), z.end(), y.begin(), y.end(), quo + i * n,
                    quo + (i + 1) * n, r.begin(), r.end());
    }

    _shrink(r);
    copy(r.cbegin() + sd, r.cbegin() + sd + rsi, rem);
    _right_shift(rem, re, ss);
  }

  // a(2n bits) / b(n bits)
  static void _divmod_d2n1n(citer a, citer ae, citer b, citer be, iter quo,
                            iter qe, iter rem, iter re) {
    const size_t asi = ae - a;
    const size_t bsi = be - b;
    const size_t qsi = qe - quo;
    const size_t rsi = re - rem;
    const size_t n = bsi;

    assert(asi == 2 * n);
    assert(qsi == n);
    assert(rsi == n + 1);
    assert(_lt(a + n, ae, b, be));

    if (n % 2 != 0 || n <= DNT) {
      _divmod_naive(a, ae, b, be, quo, qe, rem, re);
      return;
    }
    const size_t hal = n >> 1;
    vector<uint32_t> r1(n + hal + 1);
    copy(a, a + hal, r1.begin());

    _divmod_d3n2n(a + hal, ae, b, be, quo + hal, qe, r1.begin() + hal,
                  r1.end());
    _divmod_d3n2n(r1.cbegin(), r1.cend() - 1, b, be, quo, quo + hal, rem, re);
  }

  // a(3n bits) / b(2n bits)
  static void _divmod_d3n2n(citer a, citer ae, citer b, citer be, iter quo,
                            iter qe, iter rem, iter re) {
    const size_t asi = ae - a;
    const size_t bsi = be - b;
    const size_t qsi = qe - quo;
    const size_t rsi = re - rem;
    const size_t n = bsi >> 1;

    assert(asi == 3 * n);
    assert(bsi == 2 * n);
    assert(qsi == n);
    assert(rsi == 2 * n + 1);
    assert(_lt(a + n, ae, b, be));

    vector<uint32_t> d(2 * n);

    if (_lt(a + n + n, ae, b + n, be)) {
      _divmod_d2n1n(a + n, ae, b + n, be, quo, qe, rem + n, re);
      _mul(quo, qe, b, b + n, d.begin(), d.end());
    } else {
      fill(quo, qe, UINT32_MAX);

      _add(a + n, a + n + n, b + n, be, rem + n, re);
      copy(b, b + n, d.begin() + n);
      _sub(d.begin(), d.end(), b, b + n);
    }

    copy(a, a + n, rem);

    while (_lt(rem, re, d.cbegin(), d.cend())) {
      _add(rem, re, b, be);
      vector<uint32_t> one{1};
      _sub(quo, qe, one.cbegin(), one.cend());
    }
    _sub(rem, re, d.cbegin(), d.cend());
  }

  // a / b (naive)
  static void _divmod_naive(citer a, citer ae, citer b, citer be, iter quo,
                            iter qe, iter rem, iter re) {
    const size_t asi = ae - a;
    const size_t bsi = be - b;
    if (bsi == 0) {
      cerr << "Divide by Zero Exception" << endl;
      exit(1);
    }

    if (bsi == 1) {
      uint64_t car = 0;
      for (size_t i = asi - 1; 0 <= (int)i; --i) {
        uint64_t v = (car << 32) | a[i];
        quo[i] = v / (*b);
        car = v - quo[i] * (*b);
      }
      *rem = (uint32_t)car;
      return;
    }
    if (max(asi, bsi) <= 2) {
      uint64_t a64 = _iter_to_integer<uint64_t>(a, ae),
               b64 = _iter_to_integer<uint64_t>(b, be);
      _integer_to_iter(a64 / b64, quo, qe);
      _integer_to_iter(a64 % b64, rem, re);
      return;
    }
    if (_lt(a, ae, b, be)) {
      if (asi > bsi)
        ae = a + bsi;
      copy(a, ae, rem);
      return;
    }
    // B > 0xFFFFFFFF, A >= B

    // 割る数のビットを大きくする
    const int shf = __builtin_clz(*(be - 1));
    vector<uint32_t> x(asi + (__builtin_clz(*(ae - 1)) < shf ? 1 : 0));
    copy(a, ae, x.begin());
    vector<uint32_t> y(b, be);

    _left_shift(x.begin(), x.end(), shf);
    _left_shift(y.begin(), y.end(), shf);

    uint32_t yb = y.back();
    vector<uint32_t> qv(x.size() - y.size() + 1);
    vector<uint32_t> rv(x.end() - y.size(), x.end());
    for (int i = qv.size() - 1; i >= 0; i--) {
      if (rv.size() < y.size()) {
        // do nothing
      } else if (rv.size() == y.size()) {
        if (_leq(y, rv)) {
          qv[i] = 1, rv = _sub(rv, y);
        }
      } else {
        assert(y.size() + 1 == rv.size());
        uint64_t rb = rv[rv.size() - 1];
        rb <<= 32;
        rb |= rv[rv.size() - 2];
        uint64_t q = rb / yb;
        if (q > UINT32_MAX)
          q = UINT32_MAX;

        vector<uint32_t> yq = _mul(y, {(uint32_t)q});
        // 真の商は q-2 以上 q+1 以下だが自信が無いので念のため while を回す
        while (_lt(rv, yq))
          q--, yq = _sub(yq, y);
        rv = _sub(rv, yq);
        while (_leq(y, rv))
          q++, rv = _sub(rv, y);
        qv[i] = q;
      }
      if (i)
        rv.insert(begin(rv), x[i - 1]);
      _shrink(rv);
    }

    _shrink(qv);
    _right_shift(rv.begin(), rv.end(), shf);
    _shrink(rv);

    copy(qv.cbegin(), qv.cend(), quo);
    copy(rv.cbegin(), rv.cend(), rem);
  }

  // int -> string
  // 先頭かどうかに応じて zero padding するかを決める
  static string _itos(uint32_t x, bool pad) {
    string res;
    for (int i = 0; i < log; i++) {
      uint32_t d = x % 16;
      if (d < 10)
        res.push_back('0' + d);
      else if (d < 16)
        res.push_back('A' + d - 10);
      else
        assert(false);
      x /= 16;
    }
    if (!pad) {
      while (res.size() && res.back() == '0')
        res.pop_back();
      assert(!res.empty());
    }
    reverse(begin(res), end(res));
    return res;
  }

  template <typename I, enable_if_t<is_integral_v<I> ||
                                    is_same_v<I, __int128_t>> * = nullptr>
  static I _iter_to_integer(citer it, const citer end) {
    I res = 0;
    int shf = 0;
    while (it != end) {
      res |= (I)*it << shf;
      shf += 32;
      ++it;
    }
    return res;
  }

  template <typename I, enable_if_t<is_integral_v<I> ||
                                    is_same_v<I, __int128_t>> * = nullptr>
  static void _integer_to_iter(I x, iter it, const iter end) {
    if constexpr (is_signed_v<I> || is_same_v<I, __int128_t>) {
      assert(x >= 0);
    }
    while (x) {
      assert(it < end);
      *it = (uint32_t)x;
      ++it;
      x >>= 32;
    }
  }

  static vector<uint32_t> _integer_to_vector(uint32_t x) {
    return vector<uint32_t>{x};
  }

  template <typename I, enable_if_t<is_integral_v<I> ||
                                    is_same_v<I, __int128_t>> * = nullptr>
  static vector<uint32_t> _integer_to_vector(I x) {
    if constexpr (is_signed_v<I> || is_same_v<I, __int128_t>) {
      assert(x >= 0);
    }
    vector<uint32_t> rt;
    while (x) {
      rt.push_back((uint32_t)x);
      x >>= 32;
    }
    return rt;
  }

  // a << shf
  static void _left_shift(const iter a, const iter ae, int shf) {
    assert(shf < 32);
    if (shf == 0)
      return;
    const int bac = 32 - shf;
    uint32_t car = 0;
    for (iter it = a; it < ae; ++it) {
      uint32_t v = (*it << shf) | car;
      car = *it >> bac;
      *it = v;
    }
    assert(car == 0);
  }
  // a >> shf
  static void _right_shift(const iter a, const iter ae, int shf) {
    assert(shf < 32);
    if (shf == 0)
      return;
    const int bac = 32 - shf;
    uint32_t car = 0;
    for (iter it = ae - 1; a <= it; --it) {
      uint32_t v = (*it >> shf) | car;
      car = *it << bac;
      *it = v;
    }
    assert(car == 0);
  }

  // a < b
  static bool _lt(citer a, citer ae, citer b, citer be) {
    size_t asi = ae - a;
    size_t bsi = be - b;

    if (asi != bsi) {
      if (asi < bsi) {
        auto nz = std::find_if(b + asi, be, [](uint32_t x) { return x != 0; });
        if (nz != be)
          return true;

        be = b + asi;
        bsi = asi;
      } else {
        auto nz = std::find_if(a + bsi, ae, [](uint32_t x) { return x != 0; });
        if (nz != ae)
          return false;
        ae = a + bsi;
        asi = bsi;
      }
    }
    for (int i = asi - 1; i >= 0; i--) {
      if (a[i] != b[i])
        return a[i] < b[i];
    }
    return false;
  }

  static void _dump(const vector<uint32_t> &a, string s = "") {
    _dump(a.cbegin(), a.cend(), s);
  }

  static void _dump(citer a, citer ae, string s = "") {
    if (!s.empty())
      cerr << s << " : ";
    cerr << "{ ";
    for (citer it = a; it < ae; ++it) {
      cerr << *it << ", ";
    }
    cerr << "}" << endl;
  }
};

using bigint = BigInteger;

} // namespace hex_big_integer_division_internal

/// @brief Divide nonnegative hexadecimal integers stored in 32-bit limbs.
/// Karatsuba supplies subquadratic multiplication, while Burnikel-Ziegler
/// splits a normalized 2n-by-n division into balanced 3n/2-by-n and
/// n-by-n/2 subproblems; short blocks fall back to Knuth-style long division.
inline std::pair<std::string, std::string>
divide_hex_big_integers(std::string_view div, std::string_view dvs) {
  using hex_big_integer_division_internal::bigint;
  bigint fir{std::string(div)};
  bigint sec{std::string(dvs)};
  auto [qtn, rmn] = divmod(fir, sec);
  return {qtn.to_string(), rmn.to_string()};
}

} // namespace noya

#endif // NOYA_HEX_BIG_INTEGER_DIVISION_HPP
#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstdint>
#include <iostream>
#include <string>
#include <string_view>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>

/// @complexity Time: O(n^(log_2 3)) for n hexadecimal digits.
/// Space: O(n log n).

namespace noya {
namespace hex_big_integer_division_internal {

using namespace std;

struct BigInteger {
  using M = BigInteger;

  bool neg;
  vector<uint32_t> bit;
  static constexpr int log = 8;

  BigInteger() : neg(false), bit() {}

  BigInteger(bool n, const vector<uint32_t> &d) : neg(n), bit(d) {}

  BigInteger(uint32_t x) : neg(false) { bit = _integer_to_vector(x); }

  BigInteger(int32_t x) : neg(false) {
    if (x < 0)
      neg = true, x = -x;
    bit = _integer_to_vector((uint32_t)x);
  }

  template <typename I, enable_if_t<is_integral_v<I> ||
                                    is_same_v<I, __int128_t>> * = nullptr>
  BigInteger(I x) : neg(false) {
    if constexpr (is_signed_v<I> || is_same_v<I, __int128_t>) {
      if (x < 0)
        neg = true, x = -x;
    }
    bit = _integer_to_vector(x);
  }

  BigInteger(const string &S) : neg(false) {
    assert(!S.empty());
    if (S.size() == 1u && S[0] == '0')
      return;
    int l = 0;
    if (S[0] == '-')
      ++l, neg = true;

    for (int ie = S.size(); l < ie; ie -= log) {
      int is = max(l, ie - log);
      uint32_t x = 0;
      for (int i = is; i < ie; i++) {
        x <<= 4;
        if ('0' <= S[i] and S[i] <= '9') {
          x |= S[i] - '0';
        } else if ('A' <= S[i] and S[i] <= 'F') {
          x |= S[i] - 'A' + 10;
        } else if ('a' <= S[i] and S[i] <= 'f') {
          x |= S[i] - 'a' + 10;
        } else {
          assert(false);
        }
      }
      bit.push_back(x);
    }
  }

  friend M operator+(const M &lhs, const M &rhs) {
    if (lhs.neg == rhs.neg)
      return {lhs.neg, _add(lhs.bit, rhs.bit)};
    if (_leq(lhs.bit, rhs.bit)) {
      // |l| <= |r|
      auto c = _sub(rhs.bit, lhs.bit);
      bool n = _is_zero(c) ? false : rhs.neg;
      return {n, c};
    }
    auto c = _sub(lhs.bit, rhs.bit);
    bool n = _is_zero(c) ? false : lhs.neg;
    return {n, c};
  }
  friend M operator-(const M &lhs, const M &rhs) { return lhs + (-rhs); }

  friend M operator*(const M &lhs, const M &rhs) {
    auto c = _mul(lhs.bit, rhs.bit);
    bool n = _is_zero(c) ? false : (lhs.neg ^ rhs.neg);
    return {n, c};
  }
  friend pair<M, M> divmod(const M &lhs, const M &rhs) {
    auto dm = _divmod(lhs.bit, rhs.bit);
    bool dn = _is_zero(dm.first) ? false : lhs.neg != rhs.neg;
    bool mn = _is_zero(dm.second) ? false : lhs.neg;
    return {M{dn, dm.first}, M{mn, dm.second}};
  }
  friend M operator/(const M &lhs, const M &rhs) {
    return divmod(lhs, rhs).first;
  }
  friend M operator%(const M &lhs, const M &rhs) {
    return divmod(lhs, rhs).second;
  }

  M &operator+=(const M &rhs) { return (*this) = (*this) + rhs; }
  M &operator-=(const M &rhs) { return (*this) = (*this) - rhs; }
  M &operator*=(const M &rhs) { return (*this) = (*this) * rhs; }
  M &operator/=(const M &rhs) { return (*this) = (*this) / rhs; }
  M &operator%=(const M &rhs) { return (*this) = (*this) % rhs; }

  M operator-() const {
    if (is_zero())
      return *this;
    return {!neg, bit};
  }
  M operator+() const { return *this; }
  friend M abs(const M &m) { return {false, m.bit}; }
  bool is_zero() const { return _is_zero(bit); }

  friend bool operator==(const M &lhs, const M &rhs) {
    return lhs.neg == rhs.neg && lhs.bit == rhs.bit;
  }
  friend bool operator!=(const M &lhs, const M &rhs) {
    return lhs.neg != rhs.neg || lhs.bit != rhs.bit;
  }
  friend bool operator<(const M &lhs, const M &rhs) {
    if (lhs == rhs)
      return false;
    return _neq_lt(lhs, rhs);
  }
  friend bool operator<=(const M &lhs, const M &rhs) {
    if (lhs == rhs)
      return true;
    return _neq_lt(lhs, rhs);
  }
  friend bool operator>(const M &lhs, const M &rhs) {
    if (lhs == rhs)
      return false;
    return _neq_lt(rhs, lhs);
  }
  friend bool operator>=(const M &lhs, const M &rhs) {
    if (lhs == rhs)
      return true;
    return _neq_lt(rhs, lhs);
  }

  string to_string() const {
    if (is_zero())
      return "0";
    string res;
    if (neg)
      res.push_back('-');
    for (int i = _size() - 1; i >= 0; i--) {
      res += _itos(bit[i], i != _size() - 1);
    }
    return res;
  }

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

  friend ostream &operator<<(ostream &os, const M &m) {
    return os << m.to_string();
  }

private:
  // size
  int _size() const { return bit.size(); }
  // a == b
  static bool _eq(const vector<uint32_t> &a, const vector<uint32_t> &b) {
    return a == b;
  }
  // a < b
  static bool _lt(const vector<uint32_t> &a, const vector<uint32_t> &b) {
    return _lt(a.cbegin(), a.cend(), b.cbegin(), b.cend());
  }
  // a <= b
  static bool _leq(const vector<uint32_t> &a, const vector<uint32_t> &b) {
    return _eq(a, b) || _lt(a, b);
  }
  // a < b (s.t. a != b)
  static bool _neq_lt(const M &lhs, const M &rhs) {
    assert(lhs != rhs);
    if (lhs.neg != rhs.neg)
      return lhs.neg;
    bool f = _lt(lhs.bit, rhs.bit);
    if (f)
      return !lhs.neg;
    return lhs.neg;
  }
  // a == 0
  static bool _is_zero(const vector<uint32_t> &a) { return a.empty(); }
  // a == 1
  static bool _is_one(const vector<uint32_t> &a) {
    return (int)a.size() == 1 && a[0] == 1;
  }
  // 末尾 0 を削除
  static void _shrink(vector<uint32_t> &a) {
    while (a.size() && a.back() == 0)
      a.pop_back();
  }
  // 末尾 0 を削除
  void _shrink() {
    while (_size() && bit.back() == 0)
      bit.pop_back();
  }
  // a + b
  static vector<uint32_t> _add(const vector<uint32_t> &a,
                               const vector<uint32_t> &b) {
    vector<uint32_t> c(max<int>(a.size(), b.size()) + 1);
    _add(a.cbegin(), a.cend(), b.cbegin(), b.cend(), c.begin(), c.end());
    _shrink(c);
    return c;
  }
  // a - b
  static vector<uint32_t> _sub(const vector<uint32_t> &a,
                               const vector<uint32_t> &b) {
    assert(_leq(b, a));
    vector<uint32_t> c{a};
    _sub(c.begin(), c.end(), b.cbegin(), b.cend());
    _shrink(c);
    return c;
  }

  // a * b
  static vector<uint32_t> _mul(const vector<uint32_t> &a,
                               const vector<uint32_t> &b) {
    if (_is_zero(a) || _is_zero(b))
      return {};
    if (_is_one(a))
      return b;
    if (_is_one(b))
      return a;

    vector<uint32_t> c(a.size() + b.size());
    _mul(a.cbegin(), a.cend(), b.cbegin(), b.cend(), c.begin(), c.end());
    _shrink(c);
    return c;
  }

  // a / b
  static pair<vector<uint32_t>, vector<uint32_t>>
  _divmod(const vector<uint32_t> &a, const vector<uint32_t> &b) {
    if (_is_zero(b)) {
      cerr << "Divide by Zero Exception" << endl;
      exit(1);
    }

    if (a.size() < b.size()) {
      return {{}, a};
    }

    vector<uint32_t> q(a.size() - b.size() + 1);
    vector<uint32_t> r(b.size());

    _divmod(a.cbegin(), a.cend(), b.cbegin(), b.cend(), q.begin(), q.end(),
            r.begin(), r.end());
    _shrink(q);
    _shrink(r);
    return {q, r};
  }

  using iter = typename vector<uint32_t>::iterator;
  using citer = typename vector<uint32_t>::const_iterator;

  // a + b
  static void _add(citer a, citer ae, citer b, citer be, iter c, iter ce) {
    if (ae - a < be - b) {
      swap(a, b);
      swap(ae, be);
    }
    const size_t asi = ae - a;
    const size_t bsi = be - b;
    const size_t csi = ce - c;
    assert(asi <= csi);

    uint32_t car = 0;
    for (size_t i = 0; i < bsi; i++) {
      uint64_t v = (uint64_t)a[i] + b[i] + car;
      c[i] = (uint32_t)v;
      car = v >> 32;
    }
    for (size_t i = bsi; i < asi; i++) {
      uint64_t v = (uint64_t)a[i] + car;
      c[i] = (uint32_t)v;
      car = v >> 32;
    }
    if (car != 0) {
      assert(c + asi < ce);
      c[asi] = car;
    }
  }

  // a += b
  static void _add(iter a, iter ae, citer b, citer be) {
    const size_t asi = ae - a;
    const size_t bsi = be - b;

    uint32_t car = 0;
    for (size_t i = 0; i < bsi; i++) {
      uint64_t v = (uint64_t)a[i] + b[i] + car;
      a[i] = (uint32_t)v;
      car = v >> 32;
    }
    for (size_t i = bsi; car != 0 && i < asi; i++) {
      uint64_t v = (uint64_t)a[i] + car;
      a[i] = (uint32_t)v;
      car = v >> 32;
    }
  }
  // a -= b
  static void _sub(iter a, iter ae, citer b, citer be) {
    const size_t asi = ae - a;
    const size_t bsi = be - b;

    int32_t car = 0;
    for (size_t i = 0; i < bsi; i++) {
      int64_t v = (int64_t)a[i] - b[i] + car;
      a[i] = v;
      car = v >> 32;
    }
    for (size_t i = bsi; car != 0 && i < asi; i++) {
      int64_t v = (int64_t)a[i] + car;
      a[i] = v;
      car = v >> 32;
    }
    assert(car == 0);
  }

  // a * b
  static void _mul(citer a, citer ae, citer b, citer be, iter c, iter ce) {
    if (ae - a < be - b) {
      swap(a, b);
      swap(ae, be);
    }
    const size_t asi = ae - a;
    const size_t bsi = be - b;
    const size_t csi = ce - c;
    assert(csi == asi + bsi);

    if (bsi <= 128) {
      _mul_naive(a, ae, b, be, c, ce);
      return;
    }
    // Karatsuba reduces four half-size products to three.
    // |  A_hi  |  A_lo  |
    // |  B_hi  |  B_lo  |

    // z0 := A_lo * B_lo
    // z2 := A_hi * B_hi
    // z1 := A_hi * B_lo + A_lo * B_hi

    // z1 = (A_hi+A_lo) * (B_hi+B_lo) - z0 - z2

    // A * B = (z2<<(2*shf)) + (z1<<shf) + z0

    const size_t n = (asi + 1) >> 1;
    if (bsi <= n) {
      // |  A_hi  |  A_lo  |
      // |   0    |   B    |

      // A_lo * B
      _mul(a, a + n, b, be, c, c + n + bsi);

      vector<uint32_t> car(c + n, c + n + bsi);
      fill(c + n, c + n + bsi, 0);

      // A_hi * B
      _mul(a + n, ae, b, be, c + n, ce);

      _add(c + n, ce, car.cbegin(), car.cend());
    } else {
      // A_lo * B_lo
      _mul(a, a + n, b, b + n, c, c + n + n);

      // A_hi * B_hi
      _mul(a + n, ae, b + n, be, c + n + n, ce);

      vector<uint32_t> a1(n + 1);
      vector<uint32_t> b1(n + 1);
      vector<uint32_t> z1(2 * n + 2);
      _add(a, a + n, a + n, ae, a1.begin(), a1.end());
      _add(b, b + n, b + n, be, b1.begin(), b1.end());
      _mul(a1.cbegin(), a1.cend(), b1.cbegin(), b1.cend(), z1.begin(),
           z1.end());

      _sub(z1.begin(), z1.end(), c, c + n + n);
      _sub(z1.begin(), z1.end(), c + n + n, ce);

      _shrink(z1);
      _add(c + n, ce, z1.begin(), z1.end());
    }
  }

  // a * b (naive)
  static void _mul_naive(citer a, citer ae, citer b, citer be, iter c,
                         iter ce) {
    const size_t asi = ae - a;
    const size_t bsi = be - b;
    const size_t csi = ce - c;
    if (asi == 0 || bsi == 0)
      return;
    assert(csi == asi + bsi);

    for (size_t i = 0; i < asi; i++) {
      uint32_t car = 0;
      for (size_t j = 0; j < bsi; j++) {
        uint64_t p = 1LL * a[i] * b[j] + car + c[i + j];
        c[i + j] = p;
        car = p >> 32;
      }
      c[i + bsi] = car;
    }
  }

  static const int DNT = 64;

  // a / b
  static void _divmod(citer a, citer ae, citer b, citer be, iter quo, iter qe,
                      iter rem, iter re) {
    const size_t asi = ae - a;
    const size_t bsi = be - b;
    const size_t qsi = qe - quo;
    const size_t rsi = re - rem;

    assert(bsi > 0);
    assert(qsi == asi - bsi + 1);
    assert(rsi == bsi);

    if (min(asi - bsi, bsi) <= DNT) {
      _divmod_naive(a, ae, b, be, quo, qe, rem, re);
      return;
    }

    // Round the divisor length to balanced blocks before recursive division.

    size_t n;
    {
      size_t m = (bsi + DNT - 1) / DNT;
      if (m > 1)
        m = 1 << (32 - __builtin_clz(m - 1));

      size_t j = (bsi + m - 1) / m;
      n = j * m;
    }

    const int sd = n - bsi;
    const int ss = __builtin_clz(*(be - 1));

    vector<uint32_t> x(asi + sd + (__builtin_clz(*(ae - 1)) <= ss ? 1 : 0));
    vector<uint32_t> y(n);
    vector<uint32_t> r(n + 1);
    vector<uint32_t> z(2 * n);

    copy(a, ae, x.begin() + sd);
    copy(b, be, y.begin() + sd);

    _left_shift(x.begin() + sd, x.end(), ss);
    _left_shift(y.begin() + sd, y.end(), ss);

    size_t t = max<size_t>(2, (x.size() + n - 1) / n);
    copy(x.cbegin() + (t - 2) * n, x.cend(), z.begin());

    const size_t ql = qe - (quo + (t - 2) * n);
    if (ql < n) {
      vector<uint32_t> qq(n);
      _divmod_d2n1n(z.begin(), z.end(), y.begin(), y.end(), qq.begin(),
                    qq.end(), r.begin(), r.end());
      copy(qq.cbegin(), qq.cbegin() + ql, quo + (t - 2) * n);
    } else {
      _divmod_d2n1n(z.begin(), z.end(), y.begin(), y.end(), quo + (t - 2) * n,
                    quo + (t - 1) * n, r.begin(), r.end());
    }

    for (int i = t - 3; i >= 0; --i) {
      copy(x.begin() + i * n, x.begin() + (i + 1) * n, z.begin());
      copy(r.begin(), r.begin() + n, z.begin() + n);
      fill(r.begin(), r.end(), 0);

      _divmod_d2n1n(z.begin(), z.end(), y.begin(), y.end(), quo + i * n,
                    quo + (i + 1) * n, r.begin(), r.end());
    }

    _shrink(r);
    copy(r.cbegin() + sd, r.cbegin() + sd + rsi, rem);
    _right_shift(rem, re, ss);
  }

  // a(2n bits) / b(n bits)
  static void _divmod_d2n1n(citer a, citer ae, citer b, citer be, iter quo,
                            iter qe, iter rem, iter re) {
    const size_t asi = ae - a;
    const size_t bsi = be - b;
    const size_t qsi = qe - quo;
    const size_t rsi = re - rem;
    const size_t n = bsi;

    assert(asi == 2 * n);
    assert(qsi == n);
    assert(rsi == n + 1);
    assert(_lt(a + n, ae, b, be));

    if (n % 2 != 0 || n <= DNT) {
      _divmod_naive(a, ae, b, be, quo, qe, rem, re);
      return;
    }
    const size_t hal = n >> 1;
    vector<uint32_t> r1(n + hal + 1);
    copy(a, a + hal, r1.begin());

    _divmod_d3n2n(a + hal, ae, b, be, quo + hal, qe, r1.begin() + hal,
                  r1.end());
    _divmod_d3n2n(r1.cbegin(), r1.cend() - 1, b, be, quo, quo + hal, rem, re);
  }

  // a(3n bits) / b(2n bits)
  static void _divmod_d3n2n(citer a, citer ae, citer b, citer be, iter quo,
                            iter qe, iter rem, iter re) {
    const size_t asi = ae - a;
    const size_t bsi = be - b;
    const size_t qsi = qe - quo;
    const size_t rsi = re - rem;
    const size_t n = bsi >> 1;

    assert(asi == 3 * n);
    assert(bsi == 2 * n);
    assert(qsi == n);
    assert(rsi == 2 * n + 1);
    assert(_lt(a + n, ae, b, be));

    vector<uint32_t> d(2 * n);

    if (_lt(a + n + n, ae, b + n, be)) {
      _divmod_d2n1n(a + n, ae, b + n, be, quo, qe, rem + n, re);
      _mul(quo, qe, b, b + n, d.begin(), d.end());
    } else {
      fill(quo, qe, UINT32_MAX);

      _add(a + n, a + n + n, b + n, be, rem + n, re);
      copy(b, b + n, d.begin() + n);
      _sub(d.begin(), d.end(), b, b + n);
    }

    copy(a, a + n, rem);

    while (_lt(rem, re, d.cbegin(), d.cend())) {
      _add(rem, re, b, be);
      vector<uint32_t> one{1};
      _sub(quo, qe, one.cbegin(), one.cend());
    }
    _sub(rem, re, d.cbegin(), d.cend());
  }

  // a / b (naive)
  static void _divmod_naive(citer a, citer ae, citer b, citer be, iter quo,
                            iter qe, iter rem, iter re) {
    const size_t asi = ae - a;
    const size_t bsi = be - b;
    if (bsi == 0) {
      cerr << "Divide by Zero Exception" << endl;
      exit(1);
    }

    if (bsi == 1) {
      uint64_t car = 0;
      for (size_t i = asi - 1; 0 <= (int)i; --i) {
        uint64_t v = (car << 32) | a[i];
        quo[i] = v / (*b);
        car = v - quo[i] * (*b);
      }
      *rem = (uint32_t)car;
      return;
    }
    if (max(asi, bsi) <= 2) {
      uint64_t a64 = _iter_to_integer<uint64_t>(a, ae),
               b64 = _iter_to_integer<uint64_t>(b, be);
      _integer_to_iter(a64 / b64, quo, qe);
      _integer_to_iter(a64 % b64, rem, re);
      return;
    }
    if (_lt(a, ae, b, be)) {
      if (asi > bsi)
        ae = a + bsi;
      copy(a, ae, rem);
      return;
    }
    // B > 0xFFFFFFFF, A >= B

    // 割る数のビットを大きくする
    const int shf = __builtin_clz(*(be - 1));
    vector<uint32_t> x(asi + (__builtin_clz(*(ae - 1)) < shf ? 1 : 0));
    copy(a, ae, x.begin());
    vector<uint32_t> y(b, be);

    _left_shift(x.begin(), x.end(), shf);
    _left_shift(y.begin(), y.end(), shf);

    uint32_t yb = y.back();
    vector<uint32_t> qv(x.size() - y.size() + 1);
    vector<uint32_t> rv(x.end() - y.size(), x.end());
    for (int i = qv.size() - 1; i >= 0; i--) {
      if (rv.size() < y.size()) {
        // do nothing
      } else if (rv.size() == y.size()) {
        if (_leq(y, rv)) {
          qv[i] = 1, rv = _sub(rv, y);
        }
      } else {
        assert(y.size() + 1 == rv.size());
        uint64_t rb = rv[rv.size() - 1];
        rb <<= 32;
        rb |= rv[rv.size() - 2];
        uint64_t q = rb / yb;
        if (q > UINT32_MAX)
          q = UINT32_MAX;

        vector<uint32_t> yq = _mul(y, {(uint32_t)q});
        // 真の商は q-2 以上 q+1 以下だが自信が無いので念のため while を回す
        while (_lt(rv, yq))
          q--, yq = _sub(yq, y);
        rv = _sub(rv, yq);
        while (_leq(y, rv))
          q++, rv = _sub(rv, y);
        qv[i] = q;
      }
      if (i)
        rv.insert(begin(rv), x[i - 1]);
      _shrink(rv);
    }

    _shrink(qv);
    _right_shift(rv.begin(), rv.end(), shf);
    _shrink(rv);

    copy(qv.cbegin(), qv.cend(), quo);
    copy(rv.cbegin(), rv.cend(), rem);
  }

  // int -> string
  // 先頭かどうかに応じて zero padding するかを決める
  static string _itos(uint32_t x, bool pad) {
    string res;
    for (int i = 0; i < log; i++) {
      uint32_t d = x % 16;
      if (d < 10)
        res.push_back('0' + d);
      else if (d < 16)
        res.push_back('A' + d - 10);
      else
        assert(false);
      x /= 16;
    }
    if (!pad) {
      while (res.size() && res.back() == '0')
        res.pop_back();
      assert(!res.empty());
    }
    reverse(begin(res), end(res));
    return res;
  }

  template <typename I, enable_if_t<is_integral_v<I> ||
                                    is_same_v<I, __int128_t>> * = nullptr>
  static I _iter_to_integer(citer it, const citer end) {
    I res = 0;
    int shf = 0;
    while (it != end) {
      res |= (I)*it << shf;
      shf += 32;
      ++it;
    }
    return res;
  }

  template <typename I, enable_if_t<is_integral_v<I> ||
                                    is_same_v<I, __int128_t>> * = nullptr>
  static void _integer_to_iter(I x, iter it, const iter end) {
    if constexpr (is_signed_v<I> || is_same_v<I, __int128_t>) {
      assert(x >= 0);
    }
    while (x) {
      assert(it < end);
      *it = (uint32_t)x;
      ++it;
      x >>= 32;
    }
  }

  static vector<uint32_t> _integer_to_vector(uint32_t x) {
    return vector<uint32_t>{x};
  }

  template <typename I, enable_if_t<is_integral_v<I> ||
                                    is_same_v<I, __int128_t>> * = nullptr>
  static vector<uint32_t> _integer_to_vector(I x) {
    if constexpr (is_signed_v<I> || is_same_v<I, __int128_t>) {
      assert(x >= 0);
    }
    vector<uint32_t> rt;
    while (x) {
      rt.push_back((uint32_t)x);
      x >>= 32;
    }
    return rt;
  }

  // a << shf
  static void _left_shift(const iter a, const iter ae, int shf) {
    assert(shf < 32);
    if (shf == 0)
      return;
    const int bac = 32 - shf;
    uint32_t car = 0;
    for (iter it = a; it < ae; ++it) {
      uint32_t v = (*it << shf) | car;
      car = *it >> bac;
      *it = v;
    }
    assert(car == 0);
  }
  // a >> shf
  static void _right_shift(const iter a, const iter ae, int shf) {
    assert(shf < 32);
    if (shf == 0)
      return;
    const int bac = 32 - shf;
    uint32_t car = 0;
    for (iter it = ae - 1; a <= it; --it) {
      uint32_t v = (*it >> shf) | car;
      car = *it << bac;
      *it = v;
    }
    assert(car == 0);
  }

  // a < b
  static bool _lt(citer a, citer ae, citer b, citer be) {
    size_t asi = ae - a;
    size_t bsi = be - b;

    if (asi != bsi) {
      if (asi < bsi) {
        auto nz = std::find_if(b + asi, be, [](uint32_t x) { return x != 0; });
        if (nz != be)
          return true;

        be = b + asi;
        bsi = asi;
      } else {
        auto nz = std::find_if(a + bsi, ae, [](uint32_t x) { return x != 0; });
        if (nz != ae)
          return false;
        ae = a + bsi;
        asi = bsi;
      }
    }
    for (int i = asi - 1; i >= 0; i--) {
      if (a[i] != b[i])
        return a[i] < b[i];
    }
    return false;
  }

  static void _dump(const vector<uint32_t> &a, string s = "") {
    _dump(a.cbegin(), a.cend(), s);
  }

  static void _dump(citer a, citer ae, string s = "") {
    if (!s.empty())
      cerr << s << " : ";
    cerr << "{ ";
    for (citer it = a; it < ae; ++it) {
      cerr << *it << ", ";
    }
    cerr << "}" << endl;
  }
};

using bigint = BigInteger;

} // namespace hex_big_integer_division_internal

/// @brief Divide nonnegative hexadecimal integers stored in 32-bit limbs.
/// Karatsuba supplies subquadratic multiplication, while Burnikel-Ziegler
/// splits a normalized 2n-by-n division into balanced 3n/2-by-n and
/// n-by-n/2 subproblems; short blocks fall back to Knuth-style long division.
inline std::pair<std::string, std::string>
divide_hex_big_integers(std::string_view div, std::string_view dvs) {
  using hex_big_integer_division_internal::bigint;
  bigint fir{std::string(div)};
  bigint sec{std::string(dvs)};
  auto [qtn, rmn] = divmod(fir, sec);
  return {qtn.to_string(), rmn.to_string()};
}

} // namespace noya