1 条题解

  • 0
    @ 2026-8-6 8:47:23

    #include<bits/stdc++.h>
    using namespace std;
     
    typedef long long LL;
    const int N = 1e6 + 10;
    const LL P = 998244353;
     
    LL a[N], b[N], c[N];
    int n;
     
    // zeta 变换:对数组进行“倍数和”变换
    // 作用:将 a[i] 变为 sum_{d 是 i 的倍数} a[d](即倍数前缀和)
    // 等价于:a[i] = Σ_{j=1}^{⌊n/i⌋} a[i*j]
    // 这是迪利克雷卷积中的“zeta 变换”(在整除格上)
    void zeta(LL a[]) {
        for (int i = 1; i <= n; i ++) {
            // 从小到大,这样保证用到的都是原先的 a 数组
            for (int j = 2; j <= n / i; j ++) {
                a[i] = (a[i] + a[i * j]) % P;
            }
        }
    }
     
    // Möbius变换:zeta变换的逆变换
    // 作用:将 a[i] 从“倍数和”恢复为原值
    // 即:a[i] = Σ_{d 是 i 的倍数} μ(d/i) * 原a[d]
    // 这里用减法实现逆变换
    void mobius(LL a[]) {
        for (int i = n; i >= 1; i --) {
            // 从大到小,这样保证用到的都是还原后的 a 数组
            for (int j = 2; j <= n / i; j ++) {
                a[i] = (a[i] - a[i * j] + P) % P;
            }
        }
    }
     
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0);
     
        cin >> n;
        for (int i = 1; i <= n; i ++) {
            cin >> a[i];
        }
        for (int i = 1; i <= n; i ++) {
            cin >> b[i];
        }
     
        // 第一步:对 a 和 b 分别做 zeta 变换
        // 变换后:a[i] = Σ_{x 是 i 的倍数} a[x]
        //        b[i] = Σ_{y 是 i 的倍数} b[y]
        zeta(a);
        zeta(b);
     
        // 第二步:逐点相乘
        // 此时 c[i] = (Σ_{x 是 i 的倍数} a[x]) * (Σ_{y 是 i 的倍数} b[y])
        //         = Σ_{x,y 都是 i 的倍数} a[x] * b[y]
        for (int i = 1; i <= n; i ++) {
            c[i] = a[i] * b[i] % P;
        }
     
        // 第三步:对 c 做 Möbius 变换(逆 zeta)
        // 变换后:c[k] = Σ_{i 是 k 的倍数} μ(i/k) * 原c[i]
        // 而原c[i] = Σ_{x,y 都是 i 的倍数} a[x]*b[y]
        // 所以最终 c[k] = Σ_{x,y 满足 gcd(x,y)=k} a[x]*b[y]
        mobius(c);
     
        // 输出结果
        for (int i = 1; i <= n; i ++) {
            cout << c[i] << " ";
        }
        cout << "\n";
     
        return 0;
    }
    
    

    #include<bits/stdc++.h>
    using namespace std;
     
    typedef long long LL;
    const int N = 1e6 + 10;
    const LL P = 998244353;
     
    LL a[N], b[N], c[N];
    int n;
     
    // 约数zeta变换:对数组进行“约数和”变换
    // 作用:将 a[d] 变为 sum_{i 是 d 的约数} a[i](即约数前缀和)
    // 等价于:a[d] = Σ_{i=1}^{d} [i|d] * a[i]
    // 这是lcm卷积中的“zeta变换”(约数方向)
    void zeta(LL a[]) {
        for (int i = n; i >= 1; i --) {
            // 从大到小遍历 i 的倍数,用到的都是原数组
            for (int j = 2; j <= n / i; j ++) {
                a[i * j] = (a[i * j] + a[i]) % P;
            }
        }
    }
     
    // 约数Möbius变换:约数zeta变换的逆变换
    // 作用:将 a[d] 从“约数和”恢复为原值
    // 即:a[d] = Σ_{i 是 d 的约数} μ(d/i) * 原a[i]
    // 这里用减法实现逆变换
    void mobius(LL a[]) {
        for (int i = 1; i <= n; i ++) {
            // 从小到大遍历i的倍数,用到的都是还原后的数组
            for (int j = 2; j <= n / i; j ++) {
                a[i * j] = (a[i * j] - a[i] + P) % P;
            }
        }
    }
     
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0);
     
        cin >> n;
        for (int i = 1; i <= n; i ++) {
            cin >> a[i];
        }
        for (int i = 1; i <= n; i ++) {
            cin >> b[i];
        }
     
        // 第一步:对 a 和 b 分别做约数zeta变换
        // 变换后:a[d] = Σ_{i 是 d 的约数} a[i]
        //        b[d] = Σ_{j 是 d 的约数} b[j]
        zeta(a);
        zeta(b);
     
        // 第二步:逐点相乘
        // 此时 c[d] = (Σ_{i 是 d 的约数} a[i]) * (Σ_{j 是 d 的约数} b[j])
        //         = Σ_{i,j 都是 d 的约数} a[i] * b[j]
        //         = Σ_{i,j 满足 lcm(i,j) 是 d 的约数} a[i] * b[j]
        // 因为 i|d 且 j|d ⇔ lcm(i,j)|d
        for (int i = 1; i <= n; i ++) {
            c[i] = a[i] * b[i] % P;
        }
     
        // 第三步:对 c 做约数Möbius变换(逆约数zeta变换)
        // 变换后:c[k] = Σ_{d 是 k 的约数} μ(k/d) * 原c[d]
        // 而原c[d] = Σ_{i,j 满足 lcm(i,j)|d} a[i]*b[j]
        // 所以最终 c[k] = Σ_{i,j 满足 lcm(i,j)=k} a[i]*b[j]
        mobius(c);
     
        // 输出结果
        for (int i = 1; i <= n; i ++) {
            cout << c[i] << " ";
        }
        cout << "\n";
     
        return 0;
    }
    
    

    • 1

    信息

    ID
    3229
    时间
    500ms
    内存
    1024MiB
    难度
    10
    标签
    递交数
    4
    已通过
    2
    上传者