Luogu P2568 GCD
\(\large{题目链接}\)
\(\\\)
求:
\[\sum\limits_{p \in prime}\sum[\gcd(x,y)=p],1 \leqslant \ x,y \ \leqslant n \leqslant 10^{7}
\]
\(\\\)
当复习一下今天学习的欧拉函数,考虑式子:
\[\sum\limits_{p \in prime}\ \sum\limits_{i=1}^{n} \ \sum\limits_{j=1}^{n} [\gcd(i,j)=p] \\ \sum\limits_{p \in prime}\sum\limits_{i=1}^{\lfloor\tfrac{n}{p}\rfloor}\sum\limits_{j=1}^{\lfloor\tfrac{n}{p}\rfloor} [\gcd(i,j)=1] \\ \sum\limits_{p \in prime} \left( \sum\limits_{i=1}^{\lfloor\tfrac{n}{p}\rfloor} \left(\sum\limits_{j=1}^{i} [\gcd(i,j)=1] \times 2 \right)- \sum_{k=1}^{\lfloor\tfrac{n}{p}\rfloor}[\gcd(k,k)=1]\right)
\]
因为\(\sum_{k=1}^{i}[\gcd(k,k)]=1\)中只有\([\gcd(1,1)=1]=1\),其余都为0,对结果没有影响,所以我们可以把式子写为:
\[\sum_{p \in prime} \left( \sum\limits_{i=1}^{\lfloor\tfrac{n}{p}\rfloor} \varphi(i) \times 2 - 1\right)
\]
\(\\\)
然后我们可以求出\(\varphi(i)\)后求出\(\varphi(i)\)的前缀和,方便枚举\(prime\)时直接查询。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e7 + 5;
typedef long long ll;
ll n, cnt, vis[N], pri[N], phi[N], sum[N];
ll read() {
ll x = 0, f = 1;
char c = getchar();
while (!isdigit(c)) {
if (c == '-') f = -1;
c = getchar();
}
while (isdigit(c)) x = x * 10 + c - '0', c = getchar();
return x * f;
}
inline void varphi() {
phi[1] = 1;
for (int i = 2; i <= n; ++i) {
if (!vis[i]) {
vis[i] = i;
phi[i] = i - 1;
pri[++cnt] = i;
}
for (int j = 1; j <= cnt && pri[j] * i <= n; ++j) {
vis[i * pri[j]] = pri[j];
if (i % pri[j] != 0) phi[pri[j] * i] = (pri[j] - 1) * phi[i];
else {
phi[i * pri[j]] = phi[i] * pri[j];
break;
}
}
}
}
int main() {
n = read();
varphi();
ll ans = 0;
//for (int i = 1; i <= n; ++i) cout << phi[i] << " ";
//cout << endl;
//ans = cnt;
//phi[1] = 0;
for (int i = 1; i <= n; ++i) sum[i] = sum[i - 1] + phi[i];
for (int i = 1; i <= cnt; ++i) {
ans += (sum[n / pri[i]] << 1) - 1;
}
printf("%lld\n", ans);
return 0;
}