F Gcd Product

题意很短。主要介绍一种和 std 不同、比 std 思维量更低一些的做法。

定义 ,即 是三元组的集合。

定义 ,即两个三元组集合的积为另一个三元组的集合。

那么:通过打表可以发现, 具有积性。即对于互质的 。且当 为质数的幂次时,容易直接求出

于是只需要按线性筛的方法算出所有的 然后统计即可。实际上不需要保存所有的 ,只需要保存所有质数幂次的 即可(不然 MLE)。

时间复杂度应该是

#include <bits/stdc++.h>
#define MOD 998244353
using namespace std;
typedef pair<pair<int, int>, int> pa;
int n, a[500005], b[500005];
bool vis[500005] = {0};
int tot = 0, prime[250005];
int mintrace[500005];
int mindive[500005];
vector<pa> vec[500005], tmp[2];
inline int modadd(int x, int y){
    int t = x + y;
    return t >= MOD ? t - MOD: t;
}
int build_pk(int p, int k, int pk){
    vector<pa>& v = vec[pk];
    int tot = pk, res = 0;
    // for k' = k: 1
    v.push_back({{1, pk}, 1}), --tot;
    v.push_back({{pk, 1}, 1}), --tot;
    res = modadd(1ll * a[1] * b[pk] % MOD, 1ll * a[pk] * b[1] % MOD);

    long long j = p - 1;
    for (int i = k - 1; i >= 1; --i){
        pk /= p;
        // for k' = i: (p - 1) * p^(k - i - 1)
        v.push_back({{1, pk}, j}), tot -= j;
        v.push_back({{pk, 1}, j}), tot -= j;

        res = modadd(res, 1ll * a[1] * b[pk] % MOD * j % MOD);
        res = modadd(res, 1ll * a[pk] * b[1] % MOD * j % MOD);
        j *= p;
    }
    // for (1, 1)
    if (tot > 0){
        v.push_back({{1, 1}, tot});
        res = modadd(res, 1ll * a[1] * b[1] % MOD * tot % MOD);
    }
    return res;
}
void build_prod(vector<pa>& v1, vector<pa>& v2, vector<pa>& v){
    for (auto& p: v1)
        for (auto& p2: v2){
            int xa = p.first.first * p2.first.first;
            int ya = p.first.second * p2.first.second;
            int cntt = p.second * p2.second;
            v.push_back({{xa, ya}, cntt});
        }
}
int get_prod(int x){
    int cur = 0;
    tmp[1].clear();
    tmp[1].push_back({{1, 1}, 1});

    while (x > 1){
        int q = x / mintrace[x];
        // q: p^k
        tmp[cur].clear();
        build_prod(tmp[cur ^ 1], vec[q], tmp[cur]);
        cur ^= 1;
        x = mintrace[x];
    }

    int res = 0;
    cur ^= 1;
    for (auto& p: tmp[cur]){
        res = modadd(res, 1ll * a[p.first.first] * b[p.first.second] % MOD * p.second % MOD);
    }
    return res;
}
void solve(){
    // count for 1
    int ans = 1ll * a[1] * b[1] % MOD;
    vec[1].push_back({{1, 1}, 1});

    for (int i = 2; i <= n; ++i){
        if (!vis[i]){
            prime[++tot] = i;
            mintrace[i] = 1, mindive[i] = 1;
            ans ^= build_pk(i, 1, i);
        }
        for (int j = 1; j <= tot; ++j){
            if (prime[j] > n / i) break;
            int prod = i * prime[j];
            vis[prod] = true;
            if (i % prime[j] == 0){
                mintrace[prod] = mintrace[i];
                mindive[prod] = mindive[i] + 1;
                if (mintrace[i] == 1){
                    ans ^= build_pk(prime[j], mindive[prod], prod);
                } else {
                    ans ^= get_prod(prod);
                }
                break;
            } else {
                mintrace[prod] = i;
                ans ^= get_prod(prod);
            }
        }
    }

    printf("%d\n", ans);
}
int main(){
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
    for (int i = 1; i <= n; ++i) scanf("%d", &b[i]);

    solve();
    return 0;
}