题目大意:给你$n(1leqslant nleqslant 10^7)$,求$displaystylesumlimits_{x=1}^ndisplaystylesumlimits_{y=1}^n[(x,y)in m prime]$($(a,b)$为$a,b$的$gcd$)
题解:可以用莫比乌斯反演来做,同这道题,只需要把$m$改成$n$就行了
卡点:无
C++ Code:(莫比乌斯反演)
#include <cstdio> #include <cstring> #define maxn 10000010 using namespace std; int n; int miu[maxn], plist[maxn], ptot; int g[maxn]; bool isp[maxn]; void sieve(int n) { memset(isp, true, sizeof isp); miu[1] = 1; for (int i = 2; i < n; i++) { if (isp[i]) plist[ptot++] = i, miu[i] = -1; for (int j = 0; j < ptot && i * plist[j] < n; j++) { int tmp = i * plist[j]; isp[tmp] = false; if (i % plist[j] == 0) { miu[tmp] = 0; break; } miu[tmp] = -miu[i]; } } for (int i = 0; i < ptot; i++) { for (int j = 1; j * plist[i] < n; j++) g[j * plist[i]] += miu[j]; } for (int i = 2; i <= n; i++) g[i] += g[i - 1]; } inline int min(int a, int b) {return a < b ? a : b;} long long solve(int n, int m) { long long ans = 0; int i, j; int tmp = min(n, m); for (i = 1; i <= tmp; i = j + 1) { j = min(n / (n / i), m / (m / i)); ans += 1ll * (n / i) * (m / i) * (g[j] - g[i - 1]); } return ans; } int main() { sieve(maxn); scanf("%d", &n); printf("%lld ", solve(n, n)); return 0; }
题解:也可以用也可以用$phi$函数来做。
$$
若(x,y)==p(pin
m prime)
Rightarrow ig(dfrac{x}{p},dfrac{y}{p}ig)==1
$$
线性筛出每个数的$varphi$,再前缀和一下就行了
注意,若$x<y$$(x,y)==p$和$(y,x)==p$是两种不同的方案,但只会在算$y$时被加上,所以答案要乘二,但是当$x==y$时答案会多算一遍,所以要减去质数的个数
卡点:算$varphi$时没开$long;long$
C++ Code:(phi函数)
#include <cstdio> #include <cstring> #define maxn 10000010 using namespace std; int n; bool isp[maxn]; int plist[maxn], ptot; long long phi[maxn], ans; void sieve(int n) { memset(isp, true, sizeof isp); phi[1] = 1; for (int i = 2; i <= n; i++) { if (isp[i]) { plist[ptot++] = i; phi[i] = i - 1; } for (int j = 0; j < ptot && i * plist[j] <= n; j++) { int tmp = i * plist[j]; isp[tmp] = false; if (i % plist[j] == 0) { phi[tmp] = phi[i] * plist[j]; break; } phi[tmp] = phi[i] * phi[plist[j]]; } } } int main() { scanf("%d", &n); sieve(n); for (int i = 2; i <= n; i++) phi[i] += phi[i - 1]; for (int i = 0; i < ptot; i++) ans += phi[n / plist[i]] << 1; printf("%lld ", ans - ptot); return 0; }