YY的GCD 题解
题面:
求 \(T = 10000\) 次
\[\sum_{i=1}^n \sum_{j=1}^m [gcd(i,j) 为质数]
\]
\(n\) 、 \(m\) 规模均为 \(1e7\)。
一个常见的套路是若能找到 \(g\) 使得 \(f = g*1\) \((f、g均为数论函数)\), 则
\[\sum_{i=1}^n \sum_{j=1}^m f(gcd(i,j))
\]
\[=\sum_{i=1}^n \sum_{j=1}^m \sum_{d|gcd(i,j)} g(d)
\]
\[=\sum_{d=1}^{min(n,m)} g(d) * \lfloor \frac{n}{d} \rfloor \lfloor \frac{m}{d} \rfloor
\]
由于\(f = g * 1\) , 则 \(g = f * \mu\)。
在这道题里, \(f(n) = [n为质数]\), 则
\(g(n) = \sum_{d|n} [d为质数]\mu(\frac{n}d) = \sum_{p|n} \mu(\frac{n}p)\)
所以
\[\sum_{i=1}^n \sum_{j=1}^m [gcd(i,j) 为质数]
\]
\[= \sum_{i=1}^n \sum_{j=1}^m \sum_{d|gcd(i,j)} g(d)
\]
\[=\sum_{d=1}^{min(n,m)} g(d) * \lfloor \frac{n}{d} \rfloor \lfloor \frac{m}{d} \rfloor
\]
其中, \(g(n) = \sum_{p|n} \mu(\frac{n}p)\), 可以预处理。
总复杂度就是 \(O(n + T\sqrt n)\)。
Luogu数据不开O2 AC代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e7 + 15;
#define li long long
int m, prime[maxn], v[maxn], f[maxn];
li g[maxn];
void euler(li n) {
for(li i=2; i<=n; ++i) {
if(!v[i]) {
v[prime[++m] = i] = i;
v[i] = i;
f[i] = 1;
}
for(int j=1; j<=m; ++j) {
if(prime[j] > n/i || prime[j] > v[i]) break;
v[prime[j] * i] = prime[j];
}
}
for(int i=1; i<=n; ++i) g[i] = f[i];
for(int i=1; i<=m; ++i)
for(int j=n/prime[i]; j>0; --j)
g[prime[i] * j] -= g[j];
}
li sol(int n, int m) {
int len = min(n,m);
li res = 0ll;
for(register int i=1,j; i<=len; i=j+1) {
j = min(n/(n/i), m/(m/i));
j = min(j, len);
res += (g[j]-g[i-1]) * (n/i) * (m/i);
}
return res;
}
int main()
{
euler(10000000);
for(int i=2; i<=10000000; ++i) g[i] += g[i-1];
int t; int n,m; cin >> t; while(t--) {
scanf("%d%d", &n, &m);
cout << sol(n, m) << '\n';
}
return 0;
}```

浙公网安备 33010602011771号