2020吉林省赛 H 题 Curious(莫比乌斯反演)

题目链接 : Curious

思路

题目给了个很简洁的柿子,不用英语fw再去一句一句的翻译可针不戳。对题目中的柿子进行转化就可以转化为一个很裸的莫反问题,记 \(sum(a_i)\)\(a_i\) 出现的次数。则有

\[\sum^n_{i = 1} \sum^n_{j = 1} [\gcd(a_i, a_j)= x] = \sum^m_{i = 1} \sum^m_{j = 1} [\gcd(i, j) = x] (sum(i) sum(j)) \]

这时候就可以转化成一个比较裸的问题,简单推下柿子就行了。

推导过程

\[\begin{aligned} &\sum^n_{i = 1} \sum^n_{j = 1} [\gcd(a_i, a_j)= x] \\ & = \sum^m_{i = 1} \sum^m_{j = 1} [\gcd(i, j) = x] (sum(i) sum(j)) \\ & = \sum^{\lfloor \frac m x \rfloor}_{i = 1} \sum^{\lfloor \frac m x \rfloor}_{j = 1} [\gcd(i, j) = 1] (sum(ix) sum(jx)) \\ & = \sum^{\lfloor \frac m x \rfloor}_{i = 1} \sum^{\lfloor \frac m x \rfloor}_{j = 1} (sum(ix) sum(jx)) \sum_{d | \gcd(i, j)} \mu(d) \\ & = \sum^{\lfloor \frac m x \rfloor}_{i = 1} \sum^{\lfloor \frac m x \rfloor}_{j = 1} (sum(ix) sum(jx)) \sum_{d | i \bigwedge d | j} \mu(d) \\ & = \sum_{d = 1}^{\lfloor \frac m x \rfloor} \mu(d) \sum_{d | i}^{\lfloor \frac m x \rfloor} \sum_{d | j}^{\lfloor \frac m x \rfloor} (sum(ix) sum(jx)) \\ & = \sum_{d = 1}^{\lfloor \frac m x \rfloor} \mu(d) \sum_{i = 1}^{\lfloor \frac m {dx} \rfloor} \sum_{j = 1}^{\lfloor \frac m {dx} \rfloor} (sum(ix) sum(jx)) \\ & = \sum_{d = 1}^{\lfloor \frac m x \rfloor} \mu(d) \sum_{i = 1}^{\lfloor \frac m {dx} \rfloor} sum(ix) \sum_{j = 1}^{\lfloor \frac m {dx} \rfloor} sum(jx) \\ & = \sum_{d = 1}^{\lfloor \frac m x \rfloor} \mu(d) [\sum_{i = 1}^{\lfloor \frac m {dx} \rfloor} sum(ix)]^2 \\ \end{aligned} \]

\(f(x) = \sum_{i = 1}^{\lfloor \frac m {x} \rfloor} sum(ix) \;\;\; g(x) = \sum_{d = 1}^{\lfloor \frac m x \rfloor} \mu(d) f^2(dx)\)

即最终的答案为 \(\sum_{d = 1}^{\lfloor \frac m x \rfloor} \mu(d) f^2(dx)\)

考虑到 \(m\) 的数据范围为 \(100000\), 只需要对 \(f(x), g(x)\) 进行预处理就行。

简单思考一下复杂度

\[\mathcal{O}(\sum_{x = 1}^m(\frac m 1 + \frac m 2 + \frac m 3 + \dots + \frac m x)) = \mathcal{O}(m \log m) \]

即可以在 \(\mathcal{O}(m \log m)\) 的复杂度上预处理出来 \(f(x), g(x)\) 的前 \(m\) 项。查询结果时,给定任意 \(x\) 可以 \(\mathcal{O}(1)\) 查询。

code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;

ll mu[N], vis[N], prime[N], f[N], g[N], sum[N], n, m, k, x;
//预处理莫比乌斯函数
void Mobius()
{
    int index = 0;
    mu[1] = 1;
    for (int i = 2; i <= N; i++)
    {
        if (!vis[i])
        {
            prime[index++] = i;
            mu[i] = -1;
        }
        for (int j = 0; j < index && i * prime[j] < N; j++)
        {
            vis[i * prime[j]] = i;
            if (i % prime[j] == 0)
                break;
            mu[i * prime[j]] = -mu[i];
        }
    }
}

int main()
{
    Mobius();
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    int T;
    cin >> T;
    while (T--)
    {
        cin >> n >> m >> k;
        for (int i = 1; i <= m; i++) f[i] = g[i] = sum[i] = 0;
        //记录每个数出现的次数
        ll temp;
        for (int i = 1; i <= n; i++)
        {
            cin >> temp;
            sum[temp]++;
        }
        //O(mlogm) 预处理 f(x)
        for (int i = 1; i <= m; i++)
            for (int j = 1; j <= m / i; j++)
                f[i] += sum[i * j];
        //O(mlogm) 预处理 g(x)
        for (int i = 1; i <= m; i++)
            for (int j = 1; j <= m / i; j++)
                g[j] += mu[i] * f[i * j] * f[i * j];
        //O(1) 查询
        while (k--)
        {
            cin >> x;
            cout << g[x] << "\n";
        }
    }
    return 0;
}

\(ps:\) ”一个很裸的莫反问题“ 是官方题解原话,但官方题解并不是通过记录每个数的次数进行转化。个人认为这种做法对萌新更友好一点(逃

posted @ 2021-11-27 11:02  circletime  阅读(126)  评论(0)    收藏  举报