提交记录 131827


用户 题目 状态 得分 用时 内存 语言 代码长度
saffah_v41f1017_agg4 1005. 【模板题】高精度除法0 Accepted 100 4.201 ms 1164 KB C++17 81.43 KB
提交时间 评测时间
2026-10-17 19:18:16 2026-10-17 19:18:24
// ===== 引用区(本账号 saffah_v41f1017_agg4)=====
// [1] duck.ac 用户 saffah_cc_v41_agg1,提交 #130197 <https://duck.ac/submission/130197>
//     (1005 实时 T=4.209 ms 榜首)。本文件正文 = 该公开提交的逐字节副本 + 下方所述编译指示;
//     其自带的完整上游引用链(saffah_codex_6a_agg3 #129909/#129699/#129675/#129689/#128944/
//     #128715/#125838/#125697、HintFFT #19388、saffah_cc_v41_agg1 #129885 等账号与 URL、
//     复用内容说明)原样保留在下方。该公开提交无独立许可证声明;按站点公开条款具名引用。
// [2] duck.ac/problem/1005 题面:a 100,000 位、b 50,000 位,传统题 stdin→stdout。
// 合规:以上均为 duck.ac 公开提交;正文中以注释形式保留其全部上游引用。
// ===== 思路 =====
// 单变量试验:在底盘既有的 `#pragma GCC optimize("O3")` 与 `#pragma GCC target("fma")` 之后,
// 追加一条 `#pragma GCC optimize("align-functions=32","align-loops=32","rename-registers")`
// (纯编译参数,代码/算法/常数零改动)。依据:本队对同一 HintFFT 除法引擎在 1005e7 全尺度上的
// 判题机 A/B(align-functions=32 −3.3ms、align-loops=32 −5.8ms、rename-registers −10.9ms,
// 三者组合 −12.6ms ≈ −1.3%);本题缺口为 ~1.0%。目的:以最小改动兑现该组合并取真实读数。
// 输出应与底盘逐字节相同。
// ======================
// ===== REFERENCES =====
// [1] duck.ac 账号 **saffah_codex_6a_agg3**,提交 **#129909** <https://duck.ac/submission/129909>
//     (1005 实时 T = 4.287975 ms)—— **本发正文 = 该件的逐字节副本 + 下述三处改动**。
//     该件自带的全链引用块(含 #129699 / #129675 / #129689 / #128944 / #128715 / #125838 /
//     #125697 / #19388(HintFFT) 等账号、URL 与复用内容说明)在下方**原样保留**(仅压缩散文,
//     账号 / URL / 复用内容行**一字未删**)。
// [2] 我方在役 **#129885** <https://duck.ac/submission/129885>(4.331376 ms):r101a_ 的四枚
//     2-lane 融合核 + IO/打包刀 + r62c5_ 的 16 位 SWAR 与阈值 32 —— 均已含于 [1] 的血缘内。
// [3] 本发**三处新增**为本席原创(见思路段),未参考任何站外代码、论文或资料。
// 合规:以上均为 duck.ac 站内公开提交(题目页明示「你的代码将会被公开」);按目标原文写明
//     「原作者账号 / 原始提交地址 / 所用内容」三项 ✓
// ================
// ===== 思路 =====(seat r105b_ · 1005 · 三处逐位等价的结构改动)
// 【结论】底盘上三处最大可动点,各改一处;三处**均逐位等价**(本地值闸门 stdout 逐字节相同 +
//   判题机探针的商哈希逐位相同)。
//   ① [r105b-SWAR8]:abs_sub 的 SWAR 主环一轮吃的 limb 数 4 → 8(循环控制与分支减半)。
//   ② [r105b-PF512]:fft_dif 蝶形环(4 条 rank 间隔流)加显式预取;距离已扫 32/128/256/512。
//   ③ [r105b-EXTRACT]:试商乘法主环的元素提取由「4 次独立常量除法」改为「商链」(3 除 + 3 乘减),
//      输出四位逐位同值。
// 【判题机定价(本席静默探针,tryrun 通道,10 万位 / 5 万位真实规模,臂内极差 0.02%)】
//   底盘 #129909 = 1488.0 万拍 → 本发 = 1460.0 万拍 ⇒ **−1.89%**;同批单变量对照:① −0.99%、③ −0.77%。
// 【目的】本题为宽支(一发即翻严),靶 = 0.99T+0.001 ms = 4.246095 ms;本发为一次合并发射。
// ================
/** saffah_codex_6a_agg3 https://duck.ac/submission/129844 supplies the complete * saffah_cc_v41_agg1 https://duck.ac/submission/129885 supplies verbatim the */
/** saffah_codex_6a_agg3 https://duck.ac/submission/129832 supplies the accepted */
/** saffah_codex_6a_agg3 https://duck.ac/submission/129809 supplies the complete */
/** saffah_codex_6a_agg3 https://duck.ac/submission/129799 supplies the accepted * saffah_codex_6a_agg3 https://duck.ac/submission/129695 supplies the previously */
/** saffah_cc_v41_agg1 https://duck.ac/submission/129760 supplies the complete * saffah_codex_6a_agg3 https://duck.ac/submission/129643 and * https://duck.ac/submission/129678 supply proven normalized comparisons, */

// [1] 本发底盘 = 我方(saffah_cc_v41_agg1)在册最快件 **#129632** <https://duck.ac/submission/129632>

//     #128715/#128944 既有移植注记、更上游作者链与许可说明)原位置原文字保留于下方,未删改一行。
// [2] 本发三把刀的出处 = 对手 **saffah_codex_6a_agg3** 的公开提交(本席逐行回件核过,非按 diff 猜测):
//     (a) #129699 <https://duck.ac/submission/129699>(1005 · 4.635989 ms = 本题现役 T)

//     (b) #129675 <https://duck.ac/submission/129675>(1005 · 4.734 ms)

//     (c) #129689 <https://duck.ac/submission/129689>(1005e7 · 1180.457756 ms = 该题现役 T)

//     许可合规:该站 FAQ 明示提交代码公开、无独立许可证 ⇒ 具名引用使用。

// [1] duck.ac 用户 **saffah_cc_v41_agg1**(本账号),提交 **#128968**
//     <https://duck.ac/submission/128968>(1005 · 4.892945 ms = 我方本题在册最快件)

// [2] ★duck.ac 用户 **saffah_codex_6a_agg3**,提交 **#128944**
//     <https://duck.ac/submission/128944>(1005 · 4.872047 ms = 本题榜面 T)。

//        ② `Integer::string_in`:加 `__attribute__((target("avx2")))` + 32 字节 → 8 limb 的

// LICENSE:上述公开提交均**无独立许可证声明**、非来自任何外部仓库 ⇒ 按**具名引用**

// 【引用(逐条,全部为 duck.ac 公开提交,站点 FAQ 明示代码会被公开、无独立许可证 ⇒ 具名引用使用)】
// [A] 底盘 = 本账号 **saffah_cc_v41_agg1** 的在册最快件
//     #128669 <https://duck.ac/submission/128669>(1005)
//     #128672 <https://duck.ac/submission/128672>(1005e6)
//     #128693 <https://duck.ac/submission/128693>(1005e7)
//     (三件同源题族、正文逐字节同)。**沿用内容**:其正文全部(含文件头原有的全链引用与许可说明,

// [B] ★对手 **saffah_codex_6a_agg3** 提交 #128715 / #128716 / #128717
//     <https://duck.ac/submission/128715> <https://duck.ac/submission/128716>
//     <https://duck.ac/submission/128717>(三件逐字节同,本轮以 2.25% 反超我方 [A])。

// [A] 底盘 = duck.ac 用户 **saffah_codex_6a_agg3**,提交 **#128206 / #128209 / #128210**
//     <https://duck.ac/submission/128206>(三件逐字节同,md5 be9af3ae;1005 实时 T = 9.434486 ms)。

//     四刀 + 其 AVX2 平方环),其自带的全链引用与许可说明原样保留于下方。
// [B] 本账号 **saffah_cc_v41_agg1**:#128181 <https://duck.ac/submission/128181>(9.762335 ms,

// 许可:均为 duck.ac 公开提交(站点 FAQ:代码会被公开),无独立许可证声明 ⇒ 具名引用使用。

/** saffah_codex_6a_agg3, https://duck.ac/submission/128088, * https://duck.ac/submission/128089, https://duck.ac/submission/128090: * saffah_cc_v41_agg1, https://duck.ac/submission/128181, * https://duck.ac/submission/128184, https://duck.ac/submission/128189: * engine, with its documented inherited long-division corner limitation. */
/*- saffah_cc_v41_agg1 https://duck.ac/submission/127028, https://duck.ac/submission/127032 and https://duck.ac/submission/127038: twelve-limb long-division leaf threshold. All inherited author credits */

// [1] duck.ac 用户 saffah_codex_6a_agg3, 提交 #125838 <https://duck.ac/submission/125838>

//     用途:**本提交以此为逐字节底盘**(完整 HintFFT 分裂基 FFT + base-1000 递归除法

// [2] (保留自 [1] 的文件头)saffah_codex_maker, 提交 #125697 / #125698 / #125699
//     <https://duck.ac/submission/125697>:base-1000 递归除法与 HintFFT 引擎原作者。
// [3] (保留自 [1] 的文件头)With-Sky / HintFFT, 提交 #19388
//     <https://duck.ac/submission/19388>:上游 FFT 与整数运算;随件附带公开参考中已注明。
// [4] duck.ac 用户 saffah_cc_v41_agg1(本账号), 提交 #126801 (1008) / #126784 (1011):

/*- saffah_codex_maker, https://duck.ac/submission/125697, https://duck.ac/submission/125698 and https://duck.ac/submission/125699: - With-Sky / HintFFT, https://duck.ac/submission/19388: upstream FFT and copied the complete base-1000 recursive division and HintFFT engine. integer arithmetic as attributed in the supplied public reference. */
// Adapted from With-Sky / HintFFT, Duck public submission 19388.
// Base 1000 limits floating convolution error at the new input lengths.
/*Known inherited limitation: the twelve-limb reference and this version both */
#include <algorithm>
#include <atomic>
#include <complex>
#include <future>
#include <iostream>
#include <random>
#include <string>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <immintrin.h>
#ifndef HINT_SIMD_HPP
#define HINT_SIMD_HPP

#pragma GCC optimize("O3")
#pragma GCC optimize("align-functions=32","align-loops=32","rename-registers")
#pragma GCC target("fma")

using Complex = std::complex<double>;

struct Complex2
{
    __m256d data;
    Complex2()
    {
        data = _mm256_setzero_pd();
    }
    Complex2(double input)
    {
        data = _mm256_set1_pd(input);
    }
    Complex2(__m256d input)
    {
        data = input;
    }
    Complex2(const Complex2 &input)
    {
        data = input.data;
    }

    Complex2(double const *ptr)
    {
        data = _mm256_loadu_pd(ptr);
    }
    Complex2(Complex a)
    {
        data = _mm256_broadcast_pd((__m128d *)&a);
    }

    Complex2(const Complex *ptr)
    {
        data = _mm256_loadu_pd((const double *)ptr);
    }
    void clr()
    {
        data = _mm256_setzero_pd();
    }

    void store(Complex *a) const
    {
        _mm256_storeu_pd((double *)a, data);
    }

    template <int M>
    Complex2 element_permute() const
    {
        return _mm256_permute_pd(data, M);
    }
    Complex2 all_real() const
    {
        return _mm256_movedup_pd(data);
    }
    Complex2 all_imag() const
    {
        return element_permute<0XF>();
    }
    Complex2 swap() const
    {
        return element_permute<0X5>();
    }
    Complex2 mul_neg_i() const
    {
        static const __m256d subber{};
        return Complex2(_mm256_addsub_pd(subber, data)).swap();
    }
    Complex2 operator+(Complex2 input) const
    {
        return _mm256_add_pd(data, input.data);
    }
    Complex2 operator-(Complex2 input) const
    {
        return _mm256_sub_pd(data, input.data);
    }
    Complex2 operator*(Complex2 input) const
    {
        auto imag = _mm256_mul_pd(all_imag().data, input.swap().data);
        return _mm256_fmaddsub_pd(all_real().data, input.data, imag);
    }
    Complex2 operator/(Complex2 input) const
    {
        return _mm256_div_pd(data, input.data);
    }
};
#endif
#include <cstdlib>
static std::complex<double> *g_fft_buf = nullptr;
static size_t g_fft_cap = 0;
namespace hint
{
    using UINT_8 = uint8_t;
    using UINT_16 = uint16_t;
    using UINT_32 = uint32_t;
    using UINT_64 = uint64_t;
    using INT_32 = int32_t;
    using INT_64 = int64_t;
    using LONG = long;
    using Complex = std::complex<double>;
    constexpr double HINT_PI = 3.1415926535897932384626433832795;
    constexpr double HINT_2PI = HINT_PI * 2;
    template <typename T>
    constexpr T min_2pow(T n)
    {
        if(n<=1)return T(1);
        if constexpr(sizeof(T)<=4)
            return T(1u << (32-__builtin_clz((unsigned)(n-1))));
        else
            return T(1ull << (64-__builtin_clzll((unsigned long long)(n-1))));
    }
    template <typename T>
    inline void ary_clr(T *ptr, size_t len)
    {
        memset(ptr, 0, len * sizeof(T));
    }
    template <typename T>
    constexpr bool is_neg(T x)
    {
        return x < 0;
    }
    template <typename T>
    constexpr size_t hint_log2(T n)
    {
        T res = 0;
        while (n > 1)
        {
            n /= 2;
            res++;
        }
        return res;
    }
    template <typename T>
    constexpr bool is_odd(T x)
    {
        return static_cast<bool>(x & 1);
    }

    template <typename T>
    constexpr std::pair<T, T> div_mod(T a, T b)
    {
        return std::make_pair(a / b, a % b);
    }
    template <typename T>
    void ary_copy(T *target, const T *source, size_t len)
    {
        if (len == 0 || target == source)
        {
            return;
        }
        if (len >= INT64_MAX)
        {
            throw("Ary too long\n");
        }
        std::memcpy(target, source, len * sizeof(T));
    }
    template <typename T>
    inline T *ary_realloc(T *ptr, size_t len)
    {
        if (len * sizeof(T) < INT64_MAX)
        {
            ptr = static_cast<T *>(realloc(ptr, len * sizeof(T)));
        }
        if (ptr == nullptr)
        {
            throw("realloc error");
        }
        return ptr;
    }
    template <typename T>
    constexpr T max_2pow(T n)
    {
        T res = 1;
        res <<= (sizeof(T) * 8 - 1);
        while (res > n)
        {
            res /= 2;
        }
        return res;
    }
    constexpr UINT_64 qpow(UINT_64 m, UINT_64 n, UINT_64 mod)
    {
        if (m <= 1)
        {
            return m;
        }
        UINT_64 result = 1;
        while (n > 0)
        {
            if ((n & 1) != 0)
            {
                result = result * m % mod;
            }
            m = m * m % mod;
            n >>= 1;
        }
        return result;
    }
    constexpr UINT_64 mod_inv(UINT_64 n, UINT_64 mod)
    {
        return qpow(n, mod - 2, mod);
    }
    template <typename T>
    inline void com_ary_combine_copy(Complex *target, const T &source1, size_t len1, const T &source2, size_t len2)
    {
        size_t min_len = std::min(len1, len2);
        size_t i = 0;
        /* */
        for (; i + 4 <= min_len; i += 4)
        {
            const __m128i va = _mm_loadu_si128((const __m128i *)(const void *)(&source1[i]));
            const __m128i vb = _mm_loadu_si128((const __m128i *)(const void *)(&source2[i]));
            const __m256d re = _mm256_cvtepi32_pd(va);
            const __m256d im = _mm256_cvtepi32_pd(vb);
            /* */
            const __m256d u0 = _mm256_unpacklo_pd(re, im);
            const __m256d u1 = _mm256_unpackhi_pd(re, im);
            _mm256_storeu_pd((double *)(void *)(target + i),     _mm256_permute2f128_pd(u0, u1, 0x20));
            _mm256_storeu_pd((double *)(void *)(target + i + 2), _mm256_permute2f128_pd(u0, u1, 0x31));
        }
        while (i < min_len)
        {
            target[i] = Complex(source1[i], source2[i]);
            i++;
        }
        const __m256d r40z = _mm256_setzero_pd();
        for (; i + 4 <= len1; i += 4)
        {
            const __m128i va = _mm_loadu_si128((const __m128i *)(const void *)(&source1[i]));
            const __m256d re = _mm256_cvtepi32_pd(va);
            const __m256d u0 = _mm256_unpacklo_pd(re, r40z);
            const __m256d u1 = _mm256_unpackhi_pd(re, r40z);
            _mm256_storeu_pd((double *)(void *)(target + i),     _mm256_permute2f128_pd(u0, u1, 0x20));
            _mm256_storeu_pd((double *)(void *)(target + i + 2), _mm256_permute2f128_pd(u0, u1, 0x31));
        }
        while (i < len1)
        {
            target[i] = Complex(source1[i], 0.0);
            i++;
        }
        for (; i + 4 <= len2; i += 4)
        {
            const __m128i vb = _mm_loadu_si128((const __m128i *)(const void *)(&source2[i]));
            const __m256d im = _mm256_cvtepi32_pd(vb);
            const __m256d u0 = _mm256_unpacklo_pd(r40z, im);
            const __m256d u1 = _mm256_unpackhi_pd(r40z, im);
            _mm256_storeu_pd((double *)(void *)(target + i),     _mm256_permute2f128_pd(u0, u1, 0x20));
            _mm256_storeu_pd((double *)(void *)(target + i + 2), _mm256_permute2f128_pd(u0, u1, 0x31));
        }
        while (i < len2)
        {
            target[i] = Complex(0.0, source2[i]);
            i++;
        }
    }
    namespace hint_transform
    {
        class ComplexTableY
        {
        private:
            std::vector<std::vector<Complex>> table1;
            std::vector<std::vector<Complex>> table3;
            INT_32 max_log_size = 2;
            INT_32 cur_log_size = 2;

            static constexpr size_t FAC = 1;

            ComplexTableY(const ComplexTableY &) = delete;
            ComplexTableY &operator=(const ComplexTableY &) = delete;

        public:
            ~ComplexTableY() {}

            ComplexTableY(UINT_32 max_shift)
            {
                max_shift = std::max<size_t>(max_shift, 1);
                max_log_size = max_shift;
                table1.resize(max_shift + 1);
                table3.resize(max_shift + 1);
                table1[0] = table1[1] = table3[0] = table3[1] = std::vector<Complex>{1};
                table1[2] = table3[2] = std::vector<Complex>{1};
#if TABLE_PRELOAD == 1
                expand(max_shift);
#endif
            }
            void expand(INT_32 shift)
            {
                shift = std::max<INT_32>(shift, 2);
                if (shift > max_log_size)
                {
                    throw("FFT length too long for lut\n");
                }
                for (INT_32 i = cur_log_size + 1; i <= shift; i++)
                {
                    size_t len = 1ull << i, vec_size = len * FAC / 4;
                    const double angle_scale=1.0/double(len);
                    table1[i].resize(vec_size);
                    table3[i].resize(vec_size);
                    table1[i][0] = table3[i][0] = Complex(1, 0);
                    for (size_t pos = 0; pos < vec_size / 2; pos++)
                    {
                        table1[i][pos * 2] = table1[i - 1][pos];
                        table3[i][pos * 2] = table3[i - 1][pos];
                    }
                    for (size_t pos = 1; pos < vec_size / 2; pos += 2)
                    {
                        double cos_theta = std::cos((HINT_2PI * pos) * angle_scale);
                        double sin_theta = std::sin((HINT_2PI * pos) * angle_scale);
                        table1[i][pos] = Complex(cos_theta, -sin_theta);
                        table1[i][vec_size - pos] = Complex(sin_theta, -cos_theta);
                    }
                    table1[i][vec_size / 2] = std::conj(unit_root(8, 1));
                    size_t odd=1;
                    for(;odd<vec_size/2 && odd*3<vec_size;odd+=2){
                        Complex tmp=table1[i][odd*3];
                        table3[i][odd]=tmp;
                        table3[i][vec_size-odd]=Complex(tmp.imag(),tmp.real());
                    }
                    for(;odd<vec_size/2;odd+=2){
                        Complex tmp=table1[i][len/2-odd*3];
                        tmp.real(-tmp.real());
                        table3[i][odd]=tmp;
                        table3[i][vec_size-odd]=Complex(tmp.imag(),tmp.real());
                    }
                    table3[i][vec_size / 2] = std::conj(unit_root(8, 3));
                }
                cur_log_size = std::max(cur_log_size, shift);
            }

            static Complex unit_root(double theta)
            {
                return std::polar<double>(1.0, theta);
            }

            static Complex unit_root(size_t m, size_t n)
            {
                return unit_root((HINT_2PI * n) / m);
            }

            Complex get_omega(UINT_32 shift, size_t n) const
            {
                size_t rank = 1ull << shift;
                const size_t rank_ff = rank - 1, quad_n = n << 2;

                size_t zone = quad_n >> shift; // 第几象限
                if ((quad_n & rank_ff) == 0)
                {
                    static constexpr Complex ONES[4] = {Complex(1, 0), Complex(0, -1), Complex(-1, 0), Complex(0, 1)};
                    return ONES[zone];
                }
                Complex tmp;
                if ((zone & 2) == 0)
                {
                    if ((zone & 1) == 0)
                    {
                        tmp = table1[shift][n];
                    }
                    else
                    {
                        tmp = table1[shift][rank / 2 - n];
                        tmp.real(-tmp.real());
                    }
                }
                else
                {
                    if ((zone & 1) == 0)
                    {
                        tmp = -table1[shift][n - rank / 2];
                    }
                    else
                    {
                        tmp = table1[shift][rank - n];
                        tmp.imag(-tmp.imag());
                    }
                }
                return tmp;
            }

            Complex get_omega3(UINT_32 shift, size_t n) const
            {
                return table3[shift][n];
            }

            Complex2 get_omegaX2(UINT_32 shift, size_t n) const
            {
                return Complex2(table1[shift].data() + n);
            }

            Complex2 get_omega3X2(UINT_32 shift, size_t n) const
            {
                return Complex2(table3[shift].data() + n);
            }
        };

        constexpr size_t lut_max_rank = 23;
        static ComplexTableY TABLE(lut_max_rank);

        template <typename T>
        void binary_reverse_swap(T &ary, size_t len)
        {
            size_t i = 0;
            for (size_t j = 1; j < len - 1; j++)
            {
                size_t k = len >> 1;
                i ^= k;
                while (k > i)
                {
                    k >>= 1;
                    i ^= k;
                };
                if (j < i)
                {
                    std::swap(ary[i], ary[j]);
                }
            }
        }

        template <typename SizeType = UINT_32, typename T>
        void quaternary_reverse_swap(T &ary, size_t len)
        {
            SizeType log_n = hint_log2(len);
            SizeType *rev = new SizeType[len / 4];
            rev[0] = 0;
            for (SizeType i = 1; i < len; i++)
            {
                SizeType index = (rev[i >> 2] >> 2) | ((i & 3) << (log_n - 2)); // 求rev交换数组
                if (i < len / 4)
                {
                    rev[i] = index;
                }
                if (i < index)
                {
                    std::swap(ary[i], ary[index]);
                }
            }
            delete[] rev;
        }

        template <typename T>
        inline void fft_2point(T &sum, T &diff)
        {
            T tmp0 = sum;
            T tmp1 = diff;
            sum = tmp0 + tmp1;
            diff = tmp0 - tmp1;
        }

        inline void fft_4point(Complex *input, size_t rank = 1)
        {
            Complex tmp0 = input[0];
            Complex tmp1 = input[rank];
            Complex tmp2 = input[rank * 2];
            Complex tmp3 = input[rank * 3];

            fft_2point(tmp0, tmp2);
            fft_2point(tmp1, tmp3);
            tmp3 = Complex(tmp3.imag(), -tmp3.real());

            input[0] = tmp0 + tmp1;
            input[rank] = tmp2 + tmp3;
            input[rank * 2] = tmp0 - tmp1;
            input[rank * 3] = tmp2 - tmp3;
        }
        inline void fft_dit_4point(Complex *input, size_t rank = 1)
        {
            Complex tmp0 = input[0];
            Complex tmp1 = input[rank];
            Complex tmp2 = input[rank * 2];
            Complex tmp3 = input[rank * 3];

            fft_2point(tmp0, tmp1);
            fft_2point(tmp2, tmp3);
            tmp3 = Complex(tmp3.imag(), -tmp3.real());

            input[0] = tmp0 + tmp2;
            input[rank] = tmp1 + tmp3;
            input[rank * 2] = tmp0 - tmp2;
            input[rank * 3] = tmp1 - tmp3;
        }
        inline void fft_dit_8point(Complex *input, size_t rank = 1)
        {
            Complex tmp0 = input[0];
            Complex tmp1 = input[rank];
            Complex tmp2 = input[rank * 2];
            Complex tmp3 = input[rank * 3];
            Complex tmp4 = input[rank * 4];
            Complex tmp5 = input[rank * 5];
            Complex tmp6 = input[rank * 6];
            Complex tmp7 = input[rank * 7];
            fft_2point(tmp0, tmp1);
            fft_2point(tmp2, tmp3);
            fft_2point(tmp4, tmp5);
            fft_2point(tmp6, tmp7);
            tmp3 = Complex(tmp3.imag(), -tmp3.real());
            tmp7 = Complex(tmp7.imag(), -tmp7.real());

            fft_2point(tmp0, tmp2);
            fft_2point(tmp1, tmp3);
            fft_2point(tmp4, tmp6);
            fft_2point(tmp5, tmp7);
            static constexpr double cos_1_8 = 0.70710678118654752440084436210485;
            tmp5 = cos_1_8 * Complex(tmp5.imag() + tmp5.real(), tmp5.imag() - tmp5.real());
            tmp6 = Complex(tmp6.imag(), -tmp6.real());
            tmp7 = -cos_1_8 * Complex(tmp7.real() - tmp7.imag(), tmp7.real() + tmp7.imag());

            input[0] = tmp0 + tmp4;
            input[rank] = tmp1 + tmp5;
            input[rank * 2] = tmp2 + tmp6;
            input[rank * 3] = tmp3 + tmp7;
            input[rank * 4] = tmp0 - tmp4;
            input[rank * 5] = tmp1 - tmp5;
            input[rank * 6] = tmp2 - tmp6;
            input[rank * 7] = tmp3 - tmp7;
        }

        inline void fft_dif_4point(Complex *input, size_t rank = 1)
        {
            Complex tmp0 = input[0];
            Complex tmp1 = input[rank];
            Complex tmp2 = input[rank * 2];
            Complex tmp3 = input[rank * 3];

            fft_2point(tmp0, tmp2);
            fft_2point(tmp1, tmp3);
            tmp3 = Complex(tmp3.imag(), -tmp3.real());

            input[0] = tmp0 + tmp1;
            input[rank] = tmp0 - tmp1;
            input[rank * 2] = tmp2 + tmp3;
            input[rank * 3] = tmp2 - tmp3;
        }
        inline void fft_dif_8point(Complex *input, size_t rank = 1)
        {
            Complex tmp0 = input[0];
            Complex tmp1 = input[rank];
            Complex tmp2 = input[rank * 2];
            Complex tmp3 = input[rank * 3];
            Complex tmp4 = input[rank * 4];
            Complex tmp5 = input[rank * 5];
            Complex tmp6 = input[rank * 6];
            Complex tmp7 = input[rank * 7];

            fft_2point(tmp0, tmp4);
            fft_2point(tmp1, tmp5);
            fft_2point(tmp2, tmp6);
            fft_2point(tmp3, tmp7);
            static constexpr double cos_1_8 = 0.70710678118654752440084436210485;
            tmp5 = cos_1_8 * Complex(tmp5.imag() + tmp5.real(), tmp5.imag() - tmp5.real());
            tmp6 = Complex(tmp6.imag(), -tmp6.real());
            tmp7 = -cos_1_8 * Complex(tmp7.real() - tmp7.imag(), tmp7.real() + tmp7.imag());

            fft_2point(tmp0, tmp2);
            fft_2point(tmp1, tmp3);
            fft_2point(tmp4, tmp6);
            fft_2point(tmp5, tmp7);
            tmp3 = Complex(tmp3.imag(), -tmp3.real());
            tmp7 = Complex(tmp7.imag(), -tmp7.real());

            input[0] = tmp0 + tmp1;
            input[rank] = tmp0 - tmp1;
            input[rank * 2] = tmp2 + tmp3;
            input[rank * 3] = tmp2 - tmp3;
            input[rank * 4] = tmp4 + tmp5;
            input[rank * 5] = tmp4 - tmp5;
            input[rank * 6] = tmp6 + tmp7;
            input[rank * 7] = tmp6 - tmp7;
        }

        inline void fft_radix2_dit_butterfly(Complex omega, Complex *input, size_t rank)
        {
            Complex tmp0 = input[0];
            Complex tmp1 = input[rank] * omega;
            input[0] = tmp0 + tmp1;
            input[rank] = tmp0 - tmp1;
        }

        inline void fft_radix2_dif_butterfly(Complex omega, Complex *input, size_t rank)
        {
            Complex tmp0 = input[0];
            Complex tmp1 = input[rank];
            input[0] = tmp0 + tmp1;
            input[rank] = (tmp0 - tmp1) * omega;
        }

        inline void fft_split_radix_dit_butterfly(Complex omega, Complex omega_cube,
                                                  Complex *input, size_t rank)
        {
            Complex tmp0 = input[0];
            Complex tmp1 = input[rank];
            Complex tmp2 = input[rank * 2] * omega;
            Complex tmp3 = input[rank * 3] * omega_cube;

            fft_2point(tmp2, tmp3);
            tmp3 = Complex(tmp3.imag(), -tmp3.real());

            input[0] = tmp0 + tmp2;
            input[rank] = tmp1 + tmp3;
            input[rank * 2] = tmp0 - tmp2;
            input[rank * 3] = tmp1 - tmp3;
        }

        inline void fft_split_radix_dif_butterfly(Complex omega, Complex omega_cube,
                                                  Complex *input, size_t rank)
        {
            Complex tmp0 = input[0];
            Complex tmp1 = input[rank];
            Complex tmp2 = input[rank * 2];
            Complex tmp3 = input[rank * 3];

            fft_2point(tmp0, tmp2);
            fft_2point(tmp1, tmp3);
            tmp3 = Complex(tmp3.imag(), -tmp3.real());

            input[0] = tmp0;
            input[rank] = tmp1;
            input[rank * 2] = (tmp2 + tmp3) * omega;
            input[rank * 3] = (tmp2 - tmp3) * omega_cube;
        }

        inline void fft_split_radix_dit_butterfly(Complex2 omega, Complex2 omega_cube,
                                                  Complex *input, size_t rank)
        {
            Complex2 tmp0 = input;
            Complex2 tmp1 = input + rank;
            Complex2 tmp2 = Complex2(input + rank * 2) * omega;
            Complex2 tmp3 = Complex2(input + rank * 3) * omega_cube;

            fft_2point(tmp2, tmp3);
            tmp3 = tmp3.mul_neg_i();

            (tmp0 + tmp2).store(input);
            (tmp1 + tmp3).store(input + rank);
            (tmp0 - tmp2).store(input + rank * 2);
            (tmp1 - tmp3).store(input + rank * 3);
        }

        inline void fft_split_radix_dif_butterfly(Complex2 omega, Complex2 omega_cube,
                                                  Complex *input, size_t rank)
        {
            Complex2 tmp0 = (input);
            Complex2 tmp1 = (input + rank);
            Complex2 tmp2 = (input + rank * 2);
            Complex2 tmp3 = (input + rank * 3);

            fft_2point(tmp0, tmp2);
            fft_2point(tmp1, tmp3);
            tmp3 = tmp3.mul_neg_i();

            tmp0.store(input);
            tmp1.store(input + rank);
            ((tmp2 + tmp3) * omega).store(input + rank * 2);
            ((tmp2 - tmp3) * omega_cube).store(input + rank * 3);
        }

        inline void fft_radix4_dit_butterfly(Complex omega, Complex omega_sqr, Complex omega_cube,
                                             Complex *input, size_t rank)
        {
            Complex tmp0 = input[0];
            Complex tmp1 = input[rank] * omega;
            Complex tmp2 = input[rank * 2] * omega_sqr;
            Complex tmp3 = input[rank * 3] * omega_cube;

            fft_2point(tmp0, tmp2);
            fft_2point(tmp1, tmp3);
            tmp3 = Complex(tmp3.imag(), -tmp3.real());

            input[0] = tmp0 + tmp1;
            input[rank] = tmp2 + tmp3;
            input[rank * 2] = tmp0 - tmp1;
            input[rank * 3] = tmp2 - tmp3;
        }

        inline void fft_radix4_dif_butterfly(Complex omega, Complex omega_sqr, Complex omega_cube,
                                             Complex *input, size_t rank)
        {
            Complex tmp0 = input[0];
            Complex tmp1 = input[rank];
            Complex tmp2 = input[rank * 2];
            Complex tmp3 = input[rank * 3];

            fft_2point(tmp0, tmp2);
            fft_2point(tmp1, tmp3);
            tmp3 = Complex(tmp3.imag(), -tmp3.real());

            input[0] = tmp0 + tmp1;
            input[rank] = (tmp2 + tmp3) * omega;
            input[rank * 2] = (tmp0 - tmp1) * omega_sqr;
            input[rank * 3] = (tmp2 - tmp3) * omega_cube;
        }

        inline void fft_conj(Complex *input, size_t fft_len, double div = 1)
        {
            for (size_t i = 0; i < fft_len; i++)
            {
                input[i] = std::conj(input[i]) / div;
            }
        }

        inline void fft_normalize(Complex *input, size_t fft_len)
        {
            double len = static_cast<double>(fft_len);
            for (size_t i = 0; i < fft_len; i++)
            {
                input[i] /= len;
            }
        }
/* */
#define R101A_LD(K, N)                                                                         \
__m256d v##K = _mm256_insertf128_pd(_mm256_castpd128_pd256(_mm_loadu_pd((const double *)(in + (K)))), \
_mm_loadu_pd((const double *)(in + (N) + (K))), 1);
#define R101A_ST(R, K, N)                                                                      \
_mm_storeu_pd((double *)(in + (K)), _mm256_castpd256_pd128(R));                        \
_mm_storeu_pd((double *)(in + (N) + (K)), _mm256_extractf128_pd(R, 1));
#define R101A_SIGNIM _mm256_castsi256_pd(_mm256_setr_epi64x(0, (long long)0x8000000000000000LL, 0, (long long)0x8000000000000000LL))
#define R101A_C18 _mm256_set1_pd(0.70710678118654752440084436210485)
#define R101A_MC18 _mm256_set1_pd(-0.70710678118654752440084436210485)
__attribute__((target("avx2"))) inline void fft_dif_8point_x2(Complex *in)
{
R101A_LD(0, 8) R101A_LD(1, 8) R101A_LD(2, 8) R101A_LD(3, 8)
R101A_LD(4, 8) R101A_LD(5, 8) R101A_LD(6, 8) R101A_LD(7, 8)
__m256d s04 = _mm256_add_pd(v0, v4), d04 = _mm256_sub_pd(v0, v4);
__m256d s15 = _mm256_add_pd(v1, v5), d15 = _mm256_sub_pd(v1, v5);
__m256d s26 = _mm256_add_pd(v2, v6), d26 = _mm256_sub_pd(v2, v6);
__m256d s37 = _mm256_add_pd(v3, v7), d37 = _mm256_sub_pd(v3, v7);
const __m256d sg = R101A_SIGNIM;
{   __m256d v = d15;   /* */
d15 = _mm256_mul_pd(R101A_C18, _mm256_permute_pd(_mm256_addsub_pd(_mm256_permute_pd(v, 0x5), v), 0x5)); }
d26 = _mm256_xor_pd(_mm256_permute_pd(d26, 0x5), sg);          /* */
{   __m256d v = d37;   /* */
d37 = _mm256_mul_pd(R101A_MC18, _mm256_addsub_pd(v, _mm256_permute_pd(v, 0x5))); }
__m256d u0 = _mm256_add_pd(s04, s26), u2 = _mm256_sub_pd(s04, s26);
__m256d u1 = _mm256_add_pd(s15, s37), u3 = _mm256_sub_pd(s15, s37);
__m256d u4 = _mm256_add_pd(d04, d26), u6 = _mm256_sub_pd(d04, d26);
__m256d u5 = _mm256_add_pd(d15, d37), u7 = _mm256_sub_pd(d15, d37);
u3 = _mm256_xor_pd(_mm256_permute_pd(u3, 0x5), sg);
u7 = _mm256_xor_pd(_mm256_permute_pd(u7, 0x5), sg);
R101A_ST(_mm256_add_pd(u0, u1), 0, 8) R101A_ST(_mm256_sub_pd(u0, u1), 1, 8)
R101A_ST(_mm256_add_pd(u2, u3), 2, 8) R101A_ST(_mm256_sub_pd(u2, u3), 3, 8)
R101A_ST(_mm256_add_pd(u4, u5), 4, 8) R101A_ST(_mm256_sub_pd(u4, u5), 5, 8)
R101A_ST(_mm256_add_pd(u6, u7), 6, 8) R101A_ST(_mm256_sub_pd(u6, u7), 7, 8)
}
__attribute__((target("avx2"))) inline void fft_dif_4point_x2(Complex *in)
{
R101A_LD(0, 4) R101A_LD(1, 4) R101A_LD(2, 4) R101A_LD(3, 4)
__m256d s02 = _mm256_add_pd(v0, v2), d02 = _mm256_sub_pd(v0, v2);
__m256d s13 = _mm256_add_pd(v1, v3), d13 = _mm256_sub_pd(v1, v3);
d13 = _mm256_xor_pd(_mm256_permute_pd(d13, 0x5), R101A_SIGNIM);
R101A_ST(_mm256_add_pd(s02, s13), 0, 4) R101A_ST(_mm256_sub_pd(s02, s13), 1, 4)
R101A_ST(_mm256_add_pd(d02, d13), 2, 4) R101A_ST(_mm256_sub_pd(d02, d13), 3, 4)
}
__attribute__((target("avx2"))) inline void fft_dit_8point_x2(Complex *in)
{
R101A_LD(0, 8) R101A_LD(1, 8) R101A_LD(2, 8) R101A_LD(3, 8)
R101A_LD(4, 8) R101A_LD(5, 8) R101A_LD(6, 8) R101A_LD(7, 8)
__m256d s01 = _mm256_add_pd(v0, v1), d01 = _mm256_sub_pd(v0, v1);
__m256d s23 = _mm256_add_pd(v2, v3), d23 = _mm256_sub_pd(v2, v3);
__m256d s45 = _mm256_add_pd(v4, v5), d45 = _mm256_sub_pd(v4, v5);
__m256d s67 = _mm256_add_pd(v6, v7), d67 = _mm256_sub_pd(v6, v7);
const __m256d sg = R101A_SIGNIM;
d23 = _mm256_xor_pd(_mm256_permute_pd(d23, 0x5), sg);
d67 = _mm256_xor_pd(_mm256_permute_pd(d67, 0x5), sg);
__m256d w0 = _mm256_add_pd(s01, s23), w2 = _mm256_sub_pd(s01, s23);
__m256d w1 = _mm256_add_pd(d01, d23), w3 = _mm256_sub_pd(d01, d23);
__m256d w4 = _mm256_add_pd(s45, s67), w6 = _mm256_sub_pd(s45, s67);
__m256d w5 = _mm256_add_pd(d45, d67), w7 = _mm256_sub_pd(d45, d67);
{   __m256d v = w5;
w5 = _mm256_mul_pd(R101A_C18, _mm256_permute_pd(_mm256_addsub_pd(_mm256_permute_pd(v, 0x5), v), 0x5)); }
w6 = _mm256_xor_pd(_mm256_permute_pd(w6, 0x5), sg);
{   __m256d v = w7;
w7 = _mm256_mul_pd(R101A_MC18, _mm256_addsub_pd(v, _mm256_permute_pd(v, 0x5))); }
R101A_ST(_mm256_add_pd(w0, w4), 0, 8) R101A_ST(_mm256_add_pd(w1, w5), 1, 8)
R101A_ST(_mm256_add_pd(w2, w6), 2, 8) R101A_ST(_mm256_add_pd(w3, w7), 3, 8)
R101A_ST(_mm256_sub_pd(w0, w4), 4, 8) R101A_ST(_mm256_sub_pd(w1, w5), 5, 8)
R101A_ST(_mm256_sub_pd(w2, w6), 6, 8) R101A_ST(_mm256_sub_pd(w3, w7), 7, 8)
}
__attribute__((target("avx2"))) inline void fft_dit_4point_x2(Complex *in)
{
R101A_LD(0, 4) R101A_LD(1, 4) R101A_LD(2, 4) R101A_LD(3, 4)
__m256d s01 = _mm256_add_pd(v0, v1), d01 = _mm256_sub_pd(v0, v1);
__m256d s23 = _mm256_add_pd(v2, v3), d23 = _mm256_sub_pd(v2, v3);
d23 = _mm256_xor_pd(_mm256_permute_pd(d23, 0x5), R101A_SIGNIM);
R101A_ST(_mm256_add_pd(s01, s23), 0, 4) R101A_ST(_mm256_add_pd(d01, d23), 1, 4)
R101A_ST(_mm256_sub_pd(s01, s23), 2, 4) R101A_ST(_mm256_sub_pd(d01, d23), 3, 4)
}

        template <size_t LEN>
        void fft_split_radix_dit_template(Complex *input)
        {
            constexpr size_t log_len = hint_log2(LEN);
            constexpr size_t half_len = LEN / 2, quarter_len = LEN / 4;
            fft_split_radix_dit_template<half_len>(input);
            if constexpr (quarter_len == 8) fft_dit_8point_x2(input + half_len);
            else if constexpr (quarter_len == 4) fft_dit_4point_x2(input + half_len);
            else {
            fft_split_radix_dit_template<quarter_len>(input + half_len);
            fft_split_radix_dit_template<quarter_len>(input + half_len + quarter_len);
            }
            for (size_t i = 0; i < quarter_len; i += 2)
            {
                auto omega = TABLE.get_omegaX2(log_len, i);
                auto omega_cube = TABLE.get_omega3X2(log_len, i);
                fft_split_radix_dit_butterfly(omega, omega_cube, input + i, quarter_len);
            }
        }
        template <>
        void fft_split_radix_dit_template<0>(Complex *input) {}
        template <>
        void fft_split_radix_dit_template<1>(Complex *input) {}
        template <>
        void fft_split_radix_dit_template<2>(Complex *input)
        {
            fft_2point(input[0], input[1]);
        }
        template <>
        void fft_split_radix_dit_template<4>(Complex *input)
        {
            fft_dit_4point(input, 1);
        }
        template <>
        void fft_split_radix_dit_template<8>(Complex *input)
        {
            fft_dit_8point(input, 1);
        }

        template <size_t LEN>
        void fft_split_radix_dif_template(Complex *input)
        {
            constexpr size_t log_len = hint_log2(LEN);
            constexpr size_t half_len = LEN / 2, quarter_len = LEN / 4;
            for (size_t i = 0; i < quarter_len; i += 2)
            {
                if (i + 512 < quarter_len)
                {
                    const Complex *pf = input + i + 512;
                    __builtin_prefetch(pf, 1, 3);
                    __builtin_prefetch(pf + quarter_len, 1, 3);
                    __builtin_prefetch(pf + quarter_len * 2, 1, 3);
                    __builtin_prefetch(pf + quarter_len * 3, 1, 3);
                }
                auto omega = TABLE.get_omegaX2(log_len, i);
                auto omega_cube = TABLE.get_omega3X2(log_len, i);
                fft_split_radix_dif_butterfly(omega, omega_cube, input + i, quarter_len);
            }
            fft_split_radix_dif_template<half_len>(input);
            if constexpr (quarter_len == 8) fft_dif_8point_x2(input + half_len);
            else if constexpr (quarter_len == 4) fft_dif_4point_x2(input + half_len);
            else {
            fft_split_radix_dif_template<quarter_len>(input + half_len);
            fft_split_radix_dif_template<quarter_len>(input + half_len + quarter_len);
            }
        }
        template <>
        void fft_split_radix_dif_template<0>(Complex *input) {}
        template <>
        void fft_split_radix_dif_template<1>(Complex *input) {}
        template <>
        void fft_split_radix_dif_template<2>(Complex *input)
        {
            fft_2point(input[0], input[1]);
        }
        template <>
        void fft_split_radix_dif_template<4>(Complex *input)
        {
            fft_dif_4point(input, 1);
        }
        template <>
        void fft_split_radix_dif_template<8>(Complex *input)
        {
            fft_dif_8point(input, 1);
        }

        template <size_t LEN = 1>
        void fft_dit_template(Complex *input, size_t fft_len)
        {
            if (fft_len > LEN)
            {
                fft_dit_template<LEN * 2>(input, fft_len);
                return;
            }
            TABLE.expand(hint_log2(LEN));
            fft_split_radix_dit_template<LEN>(input);
        }
        template <>
        void fft_dit_template<1 << 24>(Complex *input, size_t fft_len) {}

        template <size_t LEN = 1>
        void fft_dif_template(Complex *input, size_t fft_len)
        {
            if (fft_len > LEN)
            {
                fft_dif_template<LEN * 2>(input, fft_len);
                return;
            }
            TABLE.expand(hint_log2(LEN));
            fft_split_radix_dif_template<LEN>(input);
        }
        template <>
        void fft_dif_template<1 << 24>(Complex *input, size_t fft_len) {}

        /*<https://duck.ac/submission/129689>(逐行回件核,非按 diff 猜测): [r101a-ZH1] 反向移植 saffah_codex_6a_agg3 #129689 */
        template <size_t LEN = 16>
        void fft_dif_zero_half(Complex *input, size_t fft_len)
        {
            if constexpr (LEN < (1u << 24))
            {
                if (fft_len > LEN)
                {
                    fft_dif_zero_half<LEN * 2>(input, fft_len);
                    return;
                }
                constexpr size_t half = LEN / 2, quarter = LEN / 4, lg = hint_log2(LEN);
                TABLE.expand(lg);
                for (size_t i = 0; i < quarter; i += 2)
                {
                    const Complex2 a(input + i), b(input + quarter + i);
                    const Complex2 bi = b.mul_neg_i();
                    ((a + bi) * TABLE.get_omegaX2(lg, i)).store(input + half + i);
                    ((a - bi) * TABLE.get_omega3X2(lg, i)).store(input + half + quarter + i);
                }
                fft_split_radix_dif_template<half>(input);
                if constexpr (quarter == 8) fft_dif_8point_x2(input + half);
                else if constexpr (quarter == 4) fft_dif_4point_x2(input + half);
                else {
                fft_split_radix_dif_template<quarter>(input + half);
                fft_split_radix_dif_template<quarter>(input + half + quarter);
                }
            }
        }

        inline void fft_dit(Complex *input, size_t fft_len, bool bit_rev = true)
        {
            fft_len = max_2pow(fft_len);
            if (bit_rev)
            {
                binary_reverse_swap(input, fft_len);
            }
            fft_dit_template<1>(input, fft_len);
        }

        inline void fft_dif(Complex *input, size_t fft_len, bool bit_rev = true)
        {
            fft_len = max_2pow(fft_len);
            fft_dif_template<1>(input, fft_len);
            if (bit_rev)
            {
                binary_reverse_swap(input, fft_len);
            }
        }
    }
    template <UINT_64 BASE, typename T>
    constexpr void save_num_to_ary(T ary[], UINT_64 num, size_t digit)
    {
        size_t i = digit;
        while (i > 0)
        {
            i--;
            ary[i] = num % BASE;
            num /= BASE;
        }
    }
    UINT_64 stoui64(const std::string::const_iterator &begin,
                    const std::string::const_iterator &end, const UINT_32 base = 10)
    {
        UINT_64 result = 0;
        for (auto it = begin; it < end && it - begin < 19; ++it)
        {
            result *= base;
            char c = tolower(*it);
            UINT_64 n = 0;
            if (isalnum(c))
            {
                if (isalpha(c))
                {
                    n = c - 'a' + 10;
                }
                else
                {
                    n = c - '0';
                }
            }
            if (n < base)
            {
                result += n;
            }
        }
        return result;
    }
    UINT_64 stoui64(const std::string &str, const UINT_32 base = 10)
    {
        return stoui64(str.begin(), str.end(), base);
    }
    std::string ui64to_string(UINT_64 input, UINT_8 digits)
    {
        std::string result(digits, '0');
        for (UINT_8 i = 0; i < digits; i++)
        {
            result[digits - i - 1] = static_cast<char>(input % 10 + '0');
            input /= 10;
        }
        return result;
    }
    template <typename T = UINT_32, typename SIZE_TYPE = UINT_32>
    class HintVector
    {
    private:
        T *ary_ptr = nullptr;
        SIZE_TYPE sign_n_len = 0;
        SIZE_TYPE size = 0;

    public:
        ~HintVector()
        {
            if (ary_ptr != nullptr)
            {
                delete[] ary_ptr;
                ary_ptr = nullptr;
            }
        }
        HintVector()
        {
            ary_ptr = nullptr;
        }
        HintVector(SIZE_TYPE ele_size)
        {
            if (ele_size > 0)
            {
                resize(ele_size);
            }
        }
        HintVector(SIZE_TYPE ele_size, T ele)
        {
            if (ele_size > 0)
            {
                resize(ele_size);
                change_length(ele_size);
                fill_element(ele, ele_size);
            }
        }
        HintVector(const T *ary, SIZE_TYPE len)
        {
            if (ary == nullptr)
            {
                throw("Can't copy from nullptr\n");
            }
            if (len > 0)
            {
                resize(len);
                change_length(len);
                ary_copy(ary_ptr, ary, len);
            }
        }
        HintVector(const HintVector &input)
        {
            if (input.ary_ptr != nullptr)
            {
                if (ary_ptr != nullptr)
                {
                    delete[] ary_ptr;
                }
                ary_ptr = nullptr;
                size_t len = input.length();
                resize(len);
                change_length(len);
                change_sign(input.sign());
                ary_copy(ary_ptr, input.ary_ptr, len);
            }
        }
        HintVector(HintVector &&input)
        {
            if (input.ary_ptr != nullptr)
            {
                size = input.size;
                change_length(input.length());
                change_sign(input.sign());
                if (ary_ptr != nullptr)
                {
                    delete[] ary_ptr;
                }
                ary_ptr = input.ary_ptr;
                input.ary_ptr = nullptr;
            }
        }
        HintVector &operator=(const HintVector &input)
        {
            if (this != &input)
            {
                if (ary_ptr != nullptr)
                {
                    delete[] ary_ptr;
                }
                ary_ptr = nullptr;
                size_t len = input.length();
                resize(len);
                change_length(len);
                change_sign(input.sign());
                ary_copy(ary_ptr, input.ary_ptr, len);
            }
            return *this;
        }
        HintVector &operator=(HintVector &&input)
        {
            if (this != &input)
            {
                size = input.size;
                change_length(input.length());
                change_sign(input.sign());
                if (ary_ptr != nullptr)
                {
                    delete[] ary_ptr;
                }
                ary_ptr = input.ary_ptr;
                input.ary_ptr = nullptr;
            }
            return *this;
        }
        T &operator[](SIZE_TYPE index) const
        {
            return ary_ptr[index];
        }
        T *data() const
        {
            return ary_ptr;
        }
        static SIZE_TYPE size_generator(SIZE_TYPE new_size)
        {
            constexpr SIZE_TYPE SIZE_TYPE_BITS = sizeof(SIZE_TYPE) * 8;
            constexpr SIZE_TYPE SIZE_80 = (1ull << (SIZE_TYPE_BITS - 1));
            constexpr SIZE_TYPE LEN_MAX = SIZE_80 - 1;
            new_size = std::min<SIZE_TYPE>(new_size, LEN_MAX);
            if (new_size <= 2)
            {
                return 2;
            }
            else if (new_size <= 4)
            {
                return 4;
            }
            SIZE_TYPE size1 = min_2pow(new_size);
            SIZE_TYPE size2 = size1 / 2;
            size2 = size2 + size2 / 2;
            if (new_size <= size2)
            {
                return size2;
            }
            else
            {
                return size1;
            }
        }
        SIZE_TYPE length() const
        {
            constexpr SIZE_TYPE SIZE_TYPE_BITS = sizeof(SIZE_TYPE) * 8;
            constexpr SIZE_TYPE SIZE_80 = (1ull << (SIZE_TYPE_BITS - 1));
            constexpr SIZE_TYPE LEN_MAX = SIZE_80 - 1;
            return sign_n_len & LEN_MAX;
        }
        bool sign() const
        {
            constexpr SIZE_TYPE SIZE_TYPE_BITS = sizeof(SIZE_TYPE) * 8;
            constexpr SIZE_TYPE SIZE_80 = (1ull << (SIZE_TYPE_BITS - 1));
            return (SIZE_80 & sign_n_len) != 0;
        }
        /*[r101a-PACK1] 反向移植 saffah_codex_6a_agg3 #129699:容量查询(其 #129699 新增的 3 行)。 */
        SIZE_TYPE capacity() const
        {
            return size;
        }
        constexpr void resize(SIZE_TYPE new_size, SIZE_TYPE(size_func)(SIZE_TYPE) = size_generator)
        {
            new_size = size_func(new_size);
            if (ary_ptr == nullptr)
            {
                size = new_size;
                ary_ptr = new T[size];
                change_length(0);
            }
            else if (size != new_size)
            {
                size = new_size;
                ary_ptr = ary_realloc(ary_ptr, size);
                change_length(length());
            }
        }
        void change_length(SIZE_TYPE new_length)
        {
            constexpr SIZE_TYPE SIZE_TYPE_BITS = sizeof(SIZE_TYPE) * 8;
            constexpr SIZE_TYPE SIZE_80 = (1ull << (SIZE_TYPE_BITS - 1));
            constexpr SIZE_TYPE LEN_MAX = SIZE_80 - 1;
            if (new_length > LEN_MAX)
            {
                throw("Length too long\n");
            }
            new_length = std::min(new_length, size);
            bool sign_tmp = sign();
            sign_n_len = new_length;
            change_sign(sign_tmp);
        }
        void change_sign(bool is_sign)
        {
            constexpr SIZE_TYPE SIZE_TYPE_BITS = sizeof(SIZE_TYPE) * 8;
            constexpr SIZE_TYPE SIZE_80 = (1ull << (SIZE_TYPE_BITS - 1));
            constexpr SIZE_TYPE LEN_MAX = SIZE_80 - 1;
            if ((!is_sign) || length() == 0)
            {
                sign_n_len = sign_n_len & LEN_MAX;
            }
            else
            {
                sign_n_len = sign_n_len | SIZE_80;
            }
        }
        SIZE_TYPE set_true_len()
        {
            if (ary_ptr == nullptr)
            {
                return 0;
            }
            SIZE_TYPE t_len = length();
            while (t_len > 0 && ary_ptr[t_len - 1] == 0)
            {
                t_len--;
            }
            change_length(t_len);
            return length();
        }
        void fill_element(T ele, SIZE_TYPE count, SIZE_TYPE begin = 0)
        {
            if (begin >= size || ary_ptr == nullptr)
            {
                return;
            }
            if (begin + count >= size)
            {
                count = size - begin;
            }
            std::fill(ary_ptr + begin, ary_ptr + begin + count, ele);
        }
    };
}
namespace hint_arithm
{
    using namespace hint;
    using SIZE_TYPE = UINT_32;
    template <typename T>
    using hintvector = HintVector<T, SIZE_TYPE>;
    template <typename T>
    constexpr size_t ary_true_len(const T &ary, size_t len)
    {
        while (len > 0 && ary[len - 1] == 0)
        {
            len--;
        }
        return len;
    }
    template <typename T>
    constexpr INT_32 abs_compare(const T ary1[], const T ary2[], size_t len1, size_t len2)
    {
        len1 = ary_true_len(ary1, len1);
        len2 = ary_true_len(ary2, len2);
        if (len1 != len2)
        {
            return len1 > len2 ? 1 : -1;
        }
        if (ary1 == ary2)
        {
            return 0;
        }
        while (len1 > 0)
        {
            len1--;
            T num1 = ary1[len1], num2 = ary2[len1];
            if (num1 != num2)
            {
                return num1 > num2 ? 1 : -1;
            }
        }
        return 0;
    }
    template <typename T>
    constexpr INT_32 abs_compare_normalized(const T ary1[], const T ary2[], size_t len1, size_t len2)
    {
        if (len1 != len2)
        {
            return len1 > len2 ? 1 : -1;
        }
        if (ary1 == ary2)
        {
            return 0;
        }
        while (len1 > 0)
        {
            len1--;
            T num1 = ary1[len1], num2 = ary2[len1];
            if (num1 != num2)
            {
                return num1 > num2 ? 1 : -1;
            }
        }
        return 0;
    }

    template <UINT_64 BASE, bool is_carry = true, typename T>
    constexpr void abs_mul_num(const T in[], T num, T out[], size_t len)
    {
        len = ary_true_len(in, len);
        num %= BASE;
        UINT_64 prod = 0;
        if (num == 1)
        {
            ary_copy(out, in, len);
        }
        else
        {
            size_t i = 0;
            if constexpr (BASE <= 10000)
            {
                /* */
                constexpr UINT_64 B2 = BASE * BASE, B3 = B2 * BASE;
                for (; i + 3 <= len; i += 3)
                {
                    const UINT_64 packed = UINT_64(in[i]) + BASE * in[i + 1] + B2 * in[i + 2];
                    const UINT_64 value = packed * num + prod;
                    out[i] = T(value % BASE);
                    out[i + 1] = T((value / BASE) % BASE);
                    out[i + 2] = T((value / B2) % BASE);
                    prod = value / B3;
                }
            }
            for (; i < len; i++)
            {
                prod += static_cast<UINT_64>(in[i]) * num;
                std::tie(prod, out[i]) = div_mod<UINT_64>(prod, BASE);
            }
        }
        if (is_carry)
        {
            out[len] = prod;
        }
    }

    template <UINT_64 BASE, typename T>
    constexpr INT_64 abs_div_num(const T in[], T num, T out[], size_t len)
    {
        size_t pos = ary_true_len(in, len);
        num %= BASE;
        if (num == 1)
        {
            ary_copy(out, in, len);
            return 0;
        }
        UINT_64 last_rem = 0;
        if constexpr (BASE <= 10000)
        {
            /* */
            constexpr UINT_64 B2 = BASE * BASE, B3 = B2 * BASE;
            while (pos >= 3)
            {
                pos -= 3;
                const UINT_64 value = last_rem * B3 + UINT_64(in[pos + 2]) * B2
                                    + UINT_64(in[pos + 1]) * BASE + in[pos];
                const UINT_64 q = value / num;
                last_rem = value - q * num;
                out[pos] = T(q % BASE);
                out[pos + 1] = T((q / BASE) % BASE);
                out[pos + 2] = T(q / B2);
            }
        }
        while (pos > 0)
        {
            pos--;
            last_rem = last_rem * BASE + in[pos];
            std::tie(out[pos], last_rem) = div_mod<UINT_64>(last_rem, num);
        }
        return last_rem;
    }

    template <INT_64 BASE, bool is_carry = true, typename T>
    constexpr void abs_add(const T in1[], const T in2[], T out[],
                           size_t len1, size_t len2)
    {
        if (len1 < len2)
        {
            std::swap(in1, in2);
            std::swap(len1, len2);
        }
        size_t pos = 0;
        UINT_64 carry = 0;
        if constexpr (sizeof(T) == 4 && BASE <= 32768)
        {
            /* */
            constexpr unsigned long long bias = 0x10000ull - (unsigned long long)BASE;
            const unsigned long long biasq = bias * 0x0001000100010001ull;
            const __m128i ones = _mm_set1_epi32(-1);
            while (pos + 4 <= len2)
            {
                const __m128i a4 = _mm_loadu_si128((const __m128i *)(const void *)(in1 + pos));
                const __m128i b4 = _mm_loadu_si128((const __m128i *)(const void *)(in2 + pos));
                const unsigned long long va = (unsigned long long)_mm_cvtsi128_si64(_mm_packus_epi32(a4, ones));
                const unsigned long long vb = (unsigned long long)_mm_cvtsi128_si64(_mm_packus_epi32(b4, ones));
                const unsigned long long v = va + vb + (unsigned long long)carry + biasq;
                const unsigned long long m = (v >> 15) & 0x0001000100010001ull;
                const unsigned long long r = v - m * bias;
                _mm_storeu_si128((__m128i *)(void *)(out + pos),
                                 _mm_cvtepu16_epi32(_mm_cvtsi64_si128((long long)r)));
                carry = 1ull - (v >> 63);
                pos += 4;
            }
        }
        while (pos < len2)
        {
            carry += (in1[pos] + in2[pos]);
            out[pos] = carry < BASE ? carry : carry - BASE;
            carry = carry < BASE ? 0 : 1;
            pos++;
        }
        while (pos < len1 && carry > 0)
        {
            carry += in1[pos];
            out[pos] = carry < BASE ? carry : carry - BASE;
            carry = carry < BASE ? 0 : 1;
            pos++;
        }
        ary_copy(out + pos, in1 + pos, len1 - pos);
        if (is_carry)
        {
            out[len1] = carry % BASE;
        }
    }

    template <INT_64 BASE, typename T>
    constexpr void abs_sub(const T in1[], const T in2[], T out[],
                           size_t len1, size_t len2)
    {
        if (len1 < len2)
        {
            return;
        }
        size_t pos = 0;
        INT_64 borrow = 0;
        if (sizeof(T) == 4 && BASE <= 32768)
        {
            /* */
            constexpr unsigned long long bias = 0x10000ull - (unsigned long long)BASE;
            const __m128i ones = _mm_set1_epi32(-1);
            /* */
            while (pos + 8 <= len2)
            {
                const __m128i a4 = _mm_loadu_si128((const __m128i *)(const void *)(in1 + pos));
                const __m128i b4 = _mm_loadu_si128((const __m128i *)(const void *)(in2 + pos));
                const __m128i a4b = _mm_loadu_si128((const __m128i *)(const void *)(in1 + pos + 4));
                const __m128i b4b = _mm_loadu_si128((const __m128i *)(const void *)(in2 + pos + 4));
                const unsigned long long va = (unsigned long long)_mm_cvtsi128_si64(_mm_packus_epi32(a4, ones));
                const unsigned long long vb = (unsigned long long)_mm_cvtsi128_si64(_mm_packus_epi32(b4, ones));
                const unsigned long long va2 = (unsigned long long)_mm_cvtsi128_si64(_mm_packus_epi32(a4b, ones));
                const unsigned long long vb2 = (unsigned long long)_mm_cvtsi128_si64(_mm_packus_epi32(b4b, ones));
                const unsigned long long d0 = va - vb - (unsigned long long)borrow;
                const unsigned long long m = (d0 >> 15) & 0x0001000100010001ull;
                const unsigned long long d = d0 - m * bias;
                _mm_storeu_si128((__m128i *)(void *)(out + pos),
                                 _mm_cvtepu16_epi32(_mm_cvtsi64_si128((long long)d)));
                const unsigned long long carry1 = (d0 >> 63) & 1ull;
                const unsigned long long d0b = va2 - vb2 - carry1;
                const unsigned long long mb = (d0b >> 15) & 0x0001000100010001ull;
                const unsigned long long db = d0b - mb * bias;
                _mm_storeu_si128((__m128i *)(void *)(out + pos + 4),
                                 _mm_cvtepu16_epi32(_mm_cvtsi64_si128((long long)db)));
                borrow = (INT_64)((d0b >> 63) & 1ull);
                pos += 8;
            }
            while (pos + 4 <= len2)
            {
                const __m128i a4 = _mm_loadu_si128((const __m128i *)(const void *)(in1 + pos));
                const __m128i b4 = _mm_loadu_si128((const __m128i *)(const void *)(in2 + pos));
                unsigned long long va = (unsigned long long)_mm_cvtsi128_si64(_mm_packus_epi32(a4, ones));
                unsigned long long vb = (unsigned long long)_mm_cvtsi128_si64(_mm_packus_epi32(b4, ones));
                const unsigned long long d0 = va - vb - (unsigned long long)borrow;
                const unsigned long long m = (d0 >> 15) & 0x0001000100010001ull;
                const unsigned long long d = d0 - m * bias;
                _mm_storeu_si128((__m128i *)(void *)(out + pos),
                                 _mm_cvtepu16_epi32(_mm_cvtsi64_si128((long long)d)));
                borrow = (INT_64)((d0 >> 63) & 1ull);
                pos += 4;
            }
            borrow = borrow ? -1 : 0;
        }
        while (pos < len2)
        {
            borrow += (static_cast<INT_64>(in1[pos]) - in2[pos]);
            out[pos] = (T)(borrow < 0 ? borrow + BASE : borrow);
            borrow = borrow < 0 ? -1 : 0;
            pos++;
        }
        while (pos < len1 && borrow < 0)
        {
            borrow += in1[pos];
            out[pos] = borrow < 0 ? borrow + BASE : borrow;
            borrow = borrow < 0 ? -1 : 0;
            pos++;
        }
        ary_copy(out + pos, in1 + pos, len1 - pos);
    }

    template <UINT_64 BASE, typename T>
    void fft_mul(const T in1[], const T in2[], T out[],
                 size_t len1, size_t len2)
    {
        using namespace hint_transform;
        if (len1 == 0 || len2 == 0 || in1 == nullptr || in2 == nullptr)
        {
            return;
        }
        const size_t conv_res_len = len1 + len2 - 1;   // 卷积结果长度
        const size_t fft_len = min_2pow(conv_res_len); // fft长度
        if (fft_len > g_fft_cap)
        {
            std::free(g_fft_buf);
            g_fft_buf = (Complex *)std::malloc(sizeof(Complex) * fft_len);
            g_fft_cap = fft_len;
        }
        Complex *fft_ary = g_fft_buf;
        com_ary_combine_copy(fft_ary, in1, len1, in2, len2);
        /* */
        const size_t mx = len1 > len2 ? len1 : len2;
        const bool high_zero = fft_len >= 16 && mx <= fft_len / 2;
        {   // 原 new Complex[] 会逐一构造零值;复用缓冲必须显式补零
            /* */
            std::memset((void *)(fft_ary + mx), 0,
                        ((high_zero ? fft_len / 2 : fft_len) - mx) * sizeof(Complex));
        }
        if (high_zero) fft_dif_zero_half(fft_ary, fft_len);
        else fft_dif_template<1>(fft_ary, fft_len);
        double inv = -1 / (2.0 * fft_len);
        const __m256d scale_r=_mm256_set1_pd(inv);
        const __m256d scale_i=_mm256_set1_pd(-2.0*inv);
        size_t i=0;
        for(;i+2<=fft_len;i+=2){
            const __m256d v=_mm256_loadu_pd((const double *)(fft_ary+i));
            const __m256d re=_mm256_movedup_pd(v);
            const __m256d im=_mm256_permute_pd(v,15);
            const __m256d real=_mm256_mul_pd(_mm256_sub_pd(_mm256_mul_pd(re,re),_mm256_mul_pd(im,im)),scale_r);
            const __m256d imag=_mm256_mul_pd(_mm256_mul_pd(re,im),scale_i);
            _mm256_storeu_pd((double *)(fft_ary+i),_mm256_blend_pd(real,imag,10));
        }
        for(;i<fft_len;++i){
            Complex tmp=fft_ary[i];
            fft_ary[i]=std::conj(tmp*tmp*inv);
        }
        fft_dit_template<1>(fft_ary, fft_len);
        hint::UINT_64 carry = 0;
        size_t ic = 0;
        /* */
        const hint::UINT_64 r62_per = (hint::UINT_64)(BASE - 1) * (BASE - 1)
                                      * (hint::UINT_64)(BASE * BASE + BASE + 2);
        if ((hint::UINT_64)((conv_res_len + 1) / 2) <= (~0ull) / r62_per)
        {
            const hint::UINT_64 B1 = (hint::UINT_64)BASE;
            const hint::UINT_64 B2 = B1 * B1;
            const hint::UINT_64 B3 = B2 * B1;
            for (; ic + 3 <= conv_res_len; ic += 3)
            {
                const hint::UINT_64 c0 = static_cast<hint::INT_64>(fft_ary[ic    ].imag() + 0.5);
                const hint::UINT_64 c1 = static_cast<hint::INT_64>(fft_ary[ic + 1].imag() + 0.5);
                const hint::UINT_64 c2 = static_cast<hint::INT_64>(fft_ary[ic + 2].imag() + 0.5);
                const hint::UINT_64 s0 = carry + c0;
                out[ic    ] = (T)(s0 % B1);
                out[ic + 1] = (T)((s0 / B1 + c1) % B1);
                out[ic + 2] = (T)(((s0 + B1 * c1) / B2 + c2) % B1);
                carry = (s0 + B1 * c1 + B2 * c2) / B3;
            }
        }
        /* */
        {
            const hint::UINT_64 pair_per = (hint::UINT_64)(BASE - 1) * (BASE - 1)
                                         * (hint::UINT_64)(BASE + 2);
            if ((hint::UINT_64)((conv_res_len + 1) / 2) <= (~0ull) / pair_per)
            {
                for (; ic + 2 <= conv_res_len; ic += 2)
                {
                    const hint::UINT_64 c0 = static_cast<hint::INT_64>(fft_ary[ic    ].imag() + 0.5);
                    const hint::UINT_64 c1 = static_cast<hint::INT_64>(fft_ary[ic + 1].imag() + 0.5);
                    const hint::UINT_64 s0 = carry + c0;
                    out[ic] = (T)(s0 % BASE);
                    const hint::UINT_64 pair = s0 + (hint::UINT_64)BASE * c1;
                    out[ic + 1] = (T)((pair / BASE) % BASE);
                    carry = pair / ((hint::UINT_64)BASE * BASE);
                }
            }
        }
        for (; ic < conv_res_len; ic++)
        {
            carry += static_cast<hint::INT_64>(fft_ary[ic].imag() + 0.5);
            std::tie(carry, out[ic]) = div_mod<UINT_64>(carry, BASE);
        }
        out[conv_res_len] = carry % BASE;
    }

    template <UINT_64 BASE, typename T>
    constexpr T divisor_normalize(const T in[], T out[], size_t len)
    {
        if (in == out)
        {
            throw("In can't be same as out\n");
        }
        T multiplier = 1;
        if (len == 1)
        {
            multiplier = (BASE - 1) / in[0];
            out[0] = in[0] * multiplier;
        }
        else if (in[len - 1] >= (BASE / 2))
        {
            ary_copy(out, in, len);
        }
        else
        {
            multiplier = (BASE - 1) * BASE / (BASE * in[len - 1] + in[len - 2]);
            abs_mul_num<BASE, false>(in, multiplier, out, len);
            if (out[len - 1] < (BASE / 2))
            {
                multiplier++;
                abs_add<BASE, false>(out, in, out, len, len);
            }
        }
        return multiplier;
    }

    template <UINT_64 BASE, bool Prechecked=false, typename T>
    void abs_long_div(T dividend[], const T divisor[], T quot[],
                      size_t len1, size_t len2)
    {
        if constexpr(!Prechecked){
        len1 = ary_true_len(dividend, len1);
        len2 = ary_true_len(divisor, len2);
        if (divisor == nullptr || len2 == 0)
        {
            throw("Can't divide by zero\n");
        }
        if (dividend == nullptr || len1 == 0)
        {
            return;
        }
        if (abs_compare_normalized(dividend, divisor, len1, len2) < 0)
        {
            return;
        }
        }
        if (len2 == 1)
        {
            T rem = abs_div_num<BASE>(dividend, divisor[0], quot, len1);
            dividend[0] = rem;
            return;
        }
        if (!Prechecked && divisor[len2 - 1] < (BASE / 2))
        {
            throw("Can't call this proc before normalize the divisor\n");
        }
        quot[len1 - len2] = 0;
        const UINT_64 divisor_2digits = BASE * divisor[len2 - 1] + divisor[len2 - 2];
        /*<https://duck.ac/submission/128944>: reciprocal of the top divisor limb, [r87e8-BP1] back-ported verbatim from saffah_codex_6a_agg3 #128944 */
        const UINT_64 trial_top = divisor[len2 - 1];
        const UINT_64 trial_recip = (BASE <= 65536) ? UINT_32(0xffffffffu) / UINT_32(trial_top) : 0;
        (void)trial_top; (void)trial_recip;

        hintvector<T> sub(len2 + 1);
        /*[r101a-PACK1] 反向移植 saffah_codex_6a_agg3 #129675 <https://duck.ac/submission/129675>(逐行回件核): */
        static hintvector<UINT_64> triple_cache;
        const size_t groups = (BASE <= 10000) ? len2 / 3 : 0;
        if (triple_cache.capacity() < (SIZE_TYPE)groups)
        {
            triple_cache.resize((SIZE_TYPE)groups);
        }
        UINT_64 *packed = triple_cache.data();
        if constexpr (BASE <= 10000)
        {
            for (size_t g = 0; g < groups; g++)
            {
                packed[g] = UINT_64(divisor[3 * g]) + BASE * divisor[3 * g + 1]
                            + BASE * BASE * divisor[3 * g + 2];
            }
        }
        auto multiply_trial = [&](T num)
        {
            if constexpr (BASE <= 10000)
            {
                constexpr UINT_64 B2 = BASE * BASE, B3 = B2 * BASE;
                T *out = sub.data();
                UINT_64 carry = 0;
                if (num == 1)
                {
                    ary_copy(out, divisor, len2);
                }
                else
                {
                    size_t i = 0;
                    for (size_t g = 0; g < groups; g++, i += 3)
                    {
                        /* */
                        const UINT_64 value = packed[g] * num + carry;
                        const UINT_64 q2 = value / B3;
                        const UINT_64 r2 = value - q2 * B3;
                        const UINT_64 q1 = r2 / B2;
                        const UINT_64 r1 = r2 - q1 * B2;
                        const UINT_64 q0 = r1 / BASE;
                        out[i] = T(r1 - q0 * BASE);
                        out[i + 1] = T(q0);
                        out[i + 2] = T(q1);
                        carry = q2;
                    }
                    for (; i < len2; i++)
                    {
                        const UINT_64 value = UINT_64(divisor[i]) * num + carry;
                        carry = value / BASE;
                        out[i] = T(value - carry * BASE);
                    }
                }
                out[len2] = T(carry);
            }
            else
            {
                abs_mul_num<BASE, true, true>(divisor, num, sub.data(), len2);
            }
        };

        while (abs_compare_normalized(dividend, divisor, len1, len2) >= 0)
        {
            sub.change_length(len2 + 1);
            UINT_64 dividend_2digits = dividend[len1 - 1] * BASE + dividend[len1 - 2];
            T quo_digit = 0;
            size_t shift = len1 - len2;

            if (dividend_2digits > divisor_2digits)
            {
                /*<https://duck.ac/submission/129699>:本支在偶 BASE 下**恒有 quo_digit == 1** [r101a-FAST1] 反向移植 saffah_codex_6a_agg3 #129699 */
                if constexpr (BASE % 2 == 0)
                {
                    sub.data()[len2] = 0;   // 保持原 num==1 路径留下的进位槽状态
                    abs_sub<BASE>(dividend + shift, divisor, dividend + shift, len1 - shift, len2);
                    len1 = ary_true_len(dividend, len1);
                    quot[shift] = 1;
                    continue;
                }
                quo_digit = dividend_2digits / divisor_2digits;
                multiply_trial(quo_digit);
                sub.change_length(len2+(sub.data()[len2]!=0));
                size_t sub_len = sub.length();
                if (abs_compare_normalized(dividend + shift, sub.data(), len1 - shift, sub_len) < 0)
                {
                    quo_digit--;
                    abs_sub<BASE>(sub.data(), divisor, sub.data(), sub_len, len2);
                }
            }
            else if (dividend_2digits == divisor_2digits)
            {

                if (abs_compare_normalized(dividend + shift, divisor, len1 - shift, len2) < 0)
                {
                    quo_digit = BASE - 1;
                    shift--;
                    multiply_trial(quo_digit);
                }
                else
                {
                    quo_digit = 1;
                    ary_copy(sub.data(), divisor, len2);
                    sub.set_true_len();
                }
            }
            else
            {

                if constexpr (BASE <= 65536)
                {
                    const UINT_64 approx = (dividend_2digits * trial_recip) >> 32;
                    const UINT_64 rem = dividend_2digits - approx * trial_top;
                    quo_digit = T(approx + (rem >= trial_top));
                }
                else quo_digit = dividend_2digits / (divisor_2digits / BASE);
                if (quo_digit >= BASE)
                {
                    quo_digit = BASE - 1;
                }
                shift--;
                multiply_trial(quo_digit);
                sub.change_length(len2+(sub.data()[len2]!=0));
                size_t sub_len = sub.length();
                if (abs_compare_normalized(dividend + shift, sub.data(), len1 - shift, sub_len) < 0)
                {
                    quo_digit--;
                    abs_sub<BASE>(sub.data(), divisor, sub.data(), sub_len, len2);
                    if (abs_compare(dividend + shift, sub.data(), len1 - shift, sub_len) < 0)
                    {
                        quo_digit--;
                        abs_sub<BASE>(sub.data(), divisor, sub.data(), sub_len, len2);
                    }
                }
            }
            abs_sub<BASE>(dividend + shift, sub.data(), dividend + shift, len1 - shift, sub.length());
            len1 = ary_true_len(dividend, len1);
            quot[shift] = quo_digit;
        }
    }

    template <UINT_64 BASE, typename T>
    void abs_rec_div(T dividend[], T divisor[], hintvector<T> &quot,
                     size_t len1, size_t len2)
    {
        len1 = ary_true_len(dividend, len1);
        len2 = ary_true_len(divisor, len2);
        if (divisor == nullptr || len2 == 0)
        {
            throw("Can't divide by zero\n");
        }
        if (dividend == nullptr || len1 == 0)
        {
            return;
        }
        if (abs_compare_normalized(dividend, divisor, len1, len2) < 0)
        {
            return;
        }
        if (divisor[len2 - 1] < (BASE / 2))
        {
            throw("Can't call this proc before normalize the divisor\n");
        }
        size_t quot_len = len1 - len2 + 1;
        quot.change_length(quot_len);
        constexpr size_t LONG_DIV_THRESHOLD = 32;
        if (len2 <= LONG_DIV_THRESHOLD) // 小于等于阈值调用长除法
        {
            abs_long_div<BASE,true>(dividend, divisor, quot.data(), len1, len2);
        }
        else if (len1 >= len2 * 2 || len1 > ((len2 + 1) / 2) * 3) // 2n/n的除法,进行两次递归
        {
            size_t base_len = (len1 + 3) / 4;
            size_t quot_tmp_len = base_len * 3 - len2 + 2;
            hintvector<T> quot_tmp(quot_tmp_len, 0);

            abs_rec_div<BASE>(dividend + base_len, divisor, quot_tmp, len1 - base_len, len2);
            quot_tmp_len = quot_tmp.set_true_len();
            size_t dividend_len = ary_true_len(dividend, len1);
            abs_rec_div<BASE>(dividend, divisor, quot, dividend_len, len2);
            quot.change_length(quot_len);
            quot_len = quot.set_true_len();
            abs_add<BASE>(quot.data() + base_len, quot_tmp.data(), quot.data() + base_len, quot_len - base_len, quot_tmp_len);
            quot.change_length(len1 - len2 + 1);
        }
        else
        {

            size_t base_len = len2 / 2;
            abs_rec_div<BASE>(dividend + base_len, divisor + base_len, quot, len1 - base_len, len2 - base_len);

            constexpr T ONE[1] = {1};
            quot_len = quot.set_true_len();
            hintvector<T> prod(base_len + quot_len, 0);

            fft_mul<BASE>(divisor, quot.data(), prod.data(), base_len, quot_len);
            size_t prod_len = prod.set_true_len();
            len1 = ary_true_len(dividend, len1);
            while (abs_compare_normalized(prod.data(), dividend, prod_len, len1) > 0)
            {
                abs_sub<BASE>(quot.data(), ONE, quot.data(), quot_len, 1);
                abs_sub<BASE>(prod.data(), divisor, prod.data(), prod_len, base_len);
                abs_add<BASE>(dividend + base_len, divisor + base_len, dividend + base_len, len1 - base_len, len2 - base_len);

                quot_len = quot.set_true_len();
                prod_len = prod.set_true_len();
                len1 = ary_true_len(dividend, std::max(len1, len2) + 1);
            }
            abs_sub<BASE>(dividend, prod.data(), dividend, len1, prod_len);
        }
    }

    template <UINT_64 BASE, typename T>
    hintvector<T> abs_div(const T dividend[], T divisor[], hintvector<T> &quot,
                          size_t len1, size_t len2, bool ret_rem = true)
    {
        hintvector<T> normalized_divisor(len2); // 定义规则化的除数
        normalized_divisor.change_length(len2);
        hintvector<T> normalized_dividend(len1 + 1); // 定义规则化的被除数
        normalized_dividend.change_length(len1 + 1);

        T *divisor_ptr = normalized_divisor.data();
        T *dividend_ptr = normalized_dividend.data();
        T multiplier = divisor_normalize<BASE>(divisor, divisor_ptr, len2); // 除数规则化,获得乘数
        abs_mul_num<BASE>(dividend, multiplier, dividend_ptr, len1);        // 被除数规则化
        len1 = normalized_dividend.set_true_len();
        quot = hintvector<T>(len1 - len2 + 2, 0);

        if ((!ret_rem) && (len1 + 2 < len2 * 2))
        {

            size_t shift = len2 * 2 - len1 - 2;
            abs_rec_div<BASE>(dividend_ptr + shift, divisor_ptr + shift, quot, len1 - shift, len2 - shift);
            quot.set_true_len();
            return normalized_dividend;
        }
        abs_rec_div<BASE>(dividend_ptr, divisor_ptr, quot, len1, len2);
        quot.set_true_len();
        if (ret_rem)
        {
            len1 = normalized_dividend.set_true_len();
            abs_div_num<BASE>(dividend_ptr, multiplier, dividend_ptr, len1); // 余数除以乘数得到正确的结果
            normalized_dividend.set_true_len();
        }
        return normalized_dividend;
    }}

struct DecimalLookup {
    char digits[10000][4]{};
    constexpr DecimalLookup(){
        for(unsigned i=0;i<10000;++i){
            digits[i][0]='0'+i/1000%10;
            digits[i][1]='0'+i/100%10;
            digits[i][2]='0'+i/10%10;
            digits[i][3]='0'+i/1%10;
        }
    }
};
static constexpr DecimalLookup DECIMAL_LU{};

class Integer
{
public:
    using DataType = hint::UINT_32;
    using SizeType = hint::UINT_32;
    using DataVec = hint::HintVector<DataType, SizeType>;

private:
    DataVec data;

public:
    static constexpr hint::UINT_32 DIGIT = 4;
    static constexpr hint::UINT_64 BASE = 10000;
    Integer()
    {
        data = DataVec();
    }
    Integer(const Integer &input)
    {
        if (this != &input)
        {
            data = input.data;
        }
    }
    Integer(Integer &&input) noexcept
    {
        if (this != &input)
        {
            data = std::move(input.data);
        }
    }
    Integer &operator=(const Integer &input)
    {
        if (this != &input)
        {
            data = input.data;
        }
        return *this;
    }
    Integer &operator=(Integer &&input) noexcept
    {
        if (this != &input)
        {
            data = std::move(input.data);
        }
        return *this;
    }
    Integer &operator=(const std::string &input)
    {
        string_in(input);
        return *this;
    }
    Integer &operator=(const char input[])
    {
        string_in(input);
        return *this;
    }
    DataType first_num() const
    {
        if (length() == 0)
        {
            return 0;
        }
        return data[length() - 1];
    }
    void change_sign(bool is_neg)
    {
        data.change_sign(is_neg);
    }
    bool is_neg() const
    {
        return data.sign();
    }
    SizeType length() const
    {
        return data.length();
    }
    SizeType length_base10() const
    {
        size_t len = data.length();
        if (len == 0)
        {
            return 1;
        }
        return (len - 1) * DIGIT + std::ceil(std::log10(first_num() + 1));
    }
    void string_in(const std::string &str){string_in(str.data(),str.size());}
    /*[r101a-IO1] 反向移植 saffah_codex_6a_agg3 #129699 <https://duck.ac/submission/129699>: */
    __attribute__((target("avx2"))) void string_in(const char *str,size_t str_size)
    {
        if(str_size==0){data=DataVec();return;}
        const size_t begin=str[0]=='-'?1u:0u;
        const size_t limbs=(str_size-begin+3)/4;
        data=DataVec(limbs);
        data.change_length(limbs);
        size_t pos=str_size,i=0;
        const __m256i ascii0=_mm256_set1_epi8('0');
        const __m256i tens=_mm256_set1_epi16(0x010a);
        const __m256i hundreds=_mm256_set1_epi32(0x00010064);
        const __m256i reverse=_mm256_setr_epi32(7,6,5,4,3,2,1,0);
        while(pos-begin>=32){
            const __m256i bytes=_mm256_sub_epi8(_mm256_loadu_si256((const __m256i*)(str+pos-32)),ascii0);
            const __m256i pairs=_mm256_maddubs_epi16(bytes,tens);
            const __m256i limbs8=_mm256_madd_epi16(pairs,hundreds);
            _mm256_storeu_si256((__m256i*)(data.data()+i),_mm256_permutevar8x32_epi32(limbs8,reverse));
            pos-=32;i+=8;
        }
        while(pos-begin>=4){
            const char *p=str+pos-4;
            data[i++]=(unsigned)(p[0]-'0')*1000u+(unsigned)(p[1]-'0')*100u+(unsigned)(p[2]-'0')*10u+(unsigned)(p[3]-'0')*1u;
            pos-=4;
        }
        if(pos>begin){
            unsigned v=0;
            for(size_t k=begin;k<pos;++k)v=v*10u+(unsigned)(str[k]-'0');
            data[i]=v;
        }
        change_sign(begin!=0);
        data.set_true_len();
    }
    std::string to_string() const
    {
        size_t pos=length();
        if(!pos)return "0";
        std::string result=is_neg()?"-":"";
        result+=std::to_string(first_num());
        const size_t prefix=result.size();
        result.resize(prefix+4*(pos-1));
        char *dst=result.data()+prefix;
        --pos;
        const __m128i hundred_recip=_mm_set1_epi16(5243),hundred=_mm_set1_epi16(100);
        const __m128i ten_recip=_mm_set1_epi16(205),ten=_mm_set1_epi16(10);
        const __m128i ascii=_mm_set1_epi16(0x3030);
        while(pos>=8){
            const __m128i high=_mm_shuffle_epi32(_mm_loadu_si128((const __m128i*)(data.data()+pos-4)),0x1b);
            const __m128i low=_mm_shuffle_epi32(_mm_loadu_si128((const __m128i*)(data.data()+pos-8)),0x1b);
            const __m128i value=_mm_packus_epi32(high,low);
            const __m128i q=_mm_srli_epi16(_mm_mulhi_epu16(value,hundred_recip),3);
            const __m128i r=_mm_sub_epi16(value,_mm_mullo_epi16(q,hundred));
            const __m128i qt=_mm_srli_epi16(_mm_mullo_epi16(q,ten_recip),11);
            const __m128i rt=_mm_srli_epi16(_mm_mullo_epi16(r,ten_recip),11);
            const __m128i qo=_mm_sub_epi16(q,_mm_mullo_epi16(qt,ten));
            const __m128i ro=_mm_sub_epi16(r,_mm_mullo_epi16(rt,ten));
            const __m128i qp=_mm_add_epi16(_mm_or_si128(qt,_mm_slli_epi16(qo,8)),ascii);
            const __m128i rp=_mm_add_epi16(_mm_or_si128(rt,_mm_slli_epi16(ro,8)),ascii);
            _mm_storeu_si128((__m128i*)dst,_mm_unpacklo_epi16(qp,rp));
            _mm_storeu_si128((__m128i*)(dst+16),_mm_unpackhi_epi16(qp,rp));
            pos-=8;dst+=32;
        }
        while(pos){
            const unsigned v=data[--pos];
            std::memcpy(dst,DECIMAL_LU.digits[v],4);dst+=4;
        }
        return result;
    }
    hint::INT_32 abs_compare(const Integer &input) const
    {
        size_t len1 = length(), len2 = input.length();
        return hint_arithm::abs_compare(data.data(), input.data.data(), len1, len2);
    }
    Integer operator/(const Integer &input) const
    {
        Integer result;
        size_t len1 = length(), len2 = input.length();
        if (abs_compare(input) < 0)
        {
            return result;
        }
        if (len2 == 0)
        {
            throw("Can't divide by zero\n");
        }
        auto ptr1 = data.data();
        auto ptr2 = input.data.data();
        hint_arithm::abs_div<BASE>(ptr1, ptr2, result.data, len1, len2, false);
        result.data.set_true_len();
        result.change_sign(is_neg() != input.is_neg());
        return result;
    }
};
__attribute__((target("avx2"))) static const char* token_end(const char*p,const char*end){
    const __m256i space=_mm256_set1_epi8(32);
    while(end-p>=32){
        unsigned mask=(unsigned)_mm256_movemask_epi8(_mm256_cmpgt_epi8(_mm256_loadu_si256((const __m256i*)p),space));
        if(mask!=~0u)return p+__builtin_ctz(~mask);
        p+=32;
    }
    while(p<end&&(unsigned char)*p>32)++p;
    return p;
}
int main()
{
    std::ios::sync_with_stdio(false);std::cin.tie(nullptr);
    size_t cap=1u<<18,used=0;
    char*raw=(char*)std::malloc(cap);
    if(!raw)return 1;
    while(true){
        if(used==cap){size_t next=cap*2;char*q=(char*)std::realloc(raw,next);if(!q){std::free(raw);return 1;}raw=q;cap=next;}
        const size_t got=std::fread(raw+used,1,cap-used,stdin);used+=got;
        if(!got)break;
    }
    const char*p=raw,*end=raw+used;
    Integer a,b;
    while(p<end&&(unsigned char)*p<=32)++p;
    const char*q=token_end(p,end);a.string_in(p,q-p);p=q;
    while(p<end&&(unsigned char)*p<=32)++p;
    q=token_end(p,end);b.string_in(p,q-p);
    std::free(raw);
    std::cout<<(a/b).to_string()<<'\n';
}

CompilationN/AN/ACompile OKScore: N/A

Testcase #14.201 ms1 MB + 140 KBAcceptedScore: 100


Judge Duck Online | 评测鸭在线
Server Time: 2026-10-20 10:37:51 | Loaded in 15 ms | Server Status
个人娱乐项目,仅供学习交流使用 | 捐赠