1 条题解

  • 0
    @ 2026-8-2 21:16:09

    没学过 ntt 指路:https://blog.csdn.net/tenkuo/article/details/150500190

    #include<bits/stdc++.h>
    using namespace std;
     
    typedef long long LL;
    typedef __int128 i128;
    const int N = 3e6 + 10;
    const LL MOD = 1000000007;
     
    const LL P1 = 998244353;
    const LL P2 = 1004535809;
    const LL P3 = 469762049;
     
    LL a1[N], b1[N], a2[N], b2[N], a3[N], b3[N];
    LL ans1[N], ans2[N], ans3[N];
    LL temp_a[N], temp_b[N];
    int limit, l, r[N];
    int n, m;
     
    LL q_pow(LL a, LL b, LL P) {
        LL c = 1;
        while (b) {
            if (b & 1) c = (i128)c * a % P;
            a = (i128)a * a % P;
            b >>= 1;
        }
        return c;
    }
     
    // NTT 实现
    // type = 1: 正变换, type = -1: 逆变换
    void ntt(LL *a, int type, LL P) {
        for (int i = 0; i < limit; i++) {
            if (i < r[i]) swap(a[i], a[r[i]]);
        }
        
        for (int mid = 1; mid < limit; mid <<= 1) {
            // 计算原根 g 的 (P-1)/(2*mid) 次方
            LL Wn = q_pow(3, (P - 1) / (mid << 1), P);
            if (type == -1) {
                Wn = q_pow(Wn, P - 2, P);  // 逆变换取逆
            }
            
            for (int R = (mid << 1), j = 0; j < limit; j += R) {
                LL w = 1;
                for (int k = 0; k < mid; k++, w = (i128)w * Wn % P) {
                    LL x = a[j + k];
                    LL y = (i128)a[j + mid + k] * w % P;
                    a[j + k] = (x + y) % P;
                    a[j + mid + k] = (x - y + P) % P;
                }
            }
        }
        
        // 如果是逆变换,乘以 inv_limit
        if (type == -1) {
            LL inv_limit = q_pow(limit, P - 2, P);
            for (int i = 0; i < limit; i++) {
                a[i] = (i128)a[i] * inv_limit % P;
            }
        }
    }
     
    void cvlt(LL *a, LL *b, LL *result, LL P) {
        // 复制数据并清零剩余部分
        for (int i = 0; i < limit; i++) {
            temp_a[i] = (i < n) ? a[i] % P : 0;
            temp_b[i] = (i < m) ? b[i] % P : 0;
        }
        
        // 正变换
        ntt(temp_a, 1, P);
        ntt(temp_b, 1, P);
        
        // 点乘
        for (int i = 0; i < limit; i++) {
            temp_a[i] = (i128)temp_a[i] * temp_b[i] % P;
        }
        
        // 逆变换
        ntt(temp_a, -1, P);
        
        // 复制结果
        for (int i = 0; i < limit; i++) {
            result[i] = temp_a[i];
        }
    }
     
    LL inv(LL a, LL mod) {
        return q_pow(a, mod - 2, mod);
    }
     
    LL crt(LL r1, LL r2, LL r3) {
        LL k1 = (r2 - r1) % P2;
        if (k1 < 0) k1 += P2;
        k1 = (i128)k1 * inv(P1 % P2, P2) % P2;
        
        i128 x12 = (i128)r1 + (i128)P1 * k1;
        i128 P12 = (i128)P1 * P2;
        
        LL r3_mod = (LL)(x12 % P3);
        LL k2 = (r3 - r3_mod) % P3;
        if (k2 < 0) k2 += P3;
        k2 = (i128)k2 * inv((LL)(P12 % P3), P3) % P3;
        
        i128 x = x12 + P12 * k2;
        x %= MOD;
        
        return (LL)x;
    }
     
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0);
        
        cin >> n >> m;
        
        for (int i = 0; i < n; i++) {
            cin >> a1[i];
            a2[i] = a3[i] = a1[i];
        }
        for (int i = 0; i < m; i++) {
            cin >> b1[i];
            b2[i] = b3[i] = b1[i];
        }
        
        limit = 1;
        l = 0;
        while (limit < n + m - 1) {
            limit <<= 1;
            l ++;
        }
        
        // 计算位逆序
        for (int i = 0; i < limit; i++) {
            r[i] = (r[i >> 1] >> 1) | ((i & 1) << (l - 1));
        }
        
        // 分别在三个模数下计算卷积
        cvlt(a1, b1, ans1, P1);
        cvlt(a2, b2, ans2, P2);
        cvlt(a3, b3, ans3, P3);
        
        // 输出结果
        for (int i = 0; i < n + m - 1; i++) {
            LL res = crt(ans1[i], ans2[i], ans3[i]);
            cout << res << " ";
        }
        cout << "\n";
        
        return 0;
    }
    
    
    
    • 1

    卷积(Convolution (Mod 1,000,000,007))

    信息

    ID
    3118
    时间
    5000ms
    内存
    1024MiB
    难度
    10
    标签
    递交数
    12
    已通过
    2
    上传者