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