题解 SP26108 【TRENDGCD - Trending GCD】

Warriors_Cat

2020-12-04 08:56:23

Solution

莫比乌斯反演基础题。 ---- ### $Solution:$ 以下默认 $n \le m$,$N$ 为 $n, m$ 上限。 推式子过程有些简略,建议有一定基础再来看。 $$\begin{aligned}\text{原式}&=\sum_{i=1}^n\sum_{j=1}^mij\gcd(i, j)\mu^2(\gcd(i,j))\\&=\sum_{d=1}^nd^3\mu^2(d)\sum_{i=1}^{\left\lfloor{\frac{n}{d}}\right\rfloor}\sum_{j=1}^{\left\lfloor{\frac{m}{d}}\right\rfloor}ij[\gcd(i, j)=1]\\&=\sum_{d=1}^nd^3\mu^2(d)\sum_{i=1}^{\left\lfloor{\frac{n}{d}}\right\rfloor}\sum_{j=1}^{\left\lfloor{\frac{m}{d}}\right\rfloor}ij\sum_{k\mid\gcd(i, j)}\mu(k)\\&=\sum_{d=1}^nd^3\mu^2(d)\sum_{k=1}^{\left\lfloor{\frac{n}{d}}\right\rfloor}\mu(k)k^2\sum_{i=1}^{\left\lfloor{\frac{n}{kd}}\right\rfloor}\sum_{j=1}^{\left\lfloor{\frac{m}{kd}}\right\rfloor}ij\end{aligned}$$ 令 $S(n) =\dfrac{n(n+1)}{2}$。 $$\begin{aligned}\text{原式}&=\sum_{d=1}^n\sum_{k=1}^{\left\lfloor{\frac{n}{d}}\right\rfloor}d^3k^2\mu^2(d)\mu(k)S(\left\lfloor{\frac{n}{kd}}\right\rfloor)S(\left\lfloor{\frac{m}{kd}}\right\rfloor)\\&=\sum_{T=1}^n \sum_{d\mid T}d^3(\frac{T}{d})^2\mu^2(d)\mu(\frac{T}{d})S(\left\lfloor{\frac{n}{T}}\right\rfloor)S(\left\lfloor{\frac{m}{T}}\right\rfloor)\\&=\sum_{T=1}^nT^2\sum_{d\mid T}d\mu^2(d)\mu(\frac{T}{d})S(\left\lfloor{\frac{n}{T}}\right\rfloor)S(\left\lfloor{\frac{m}{T}}\right\rfloor)\end{aligned}$$ 令 $f(T)=\sum_{d\mid T}d\mu^2(d)\mu(\frac{T}{d})$,显然 $f(T)$ 是积性函数。 $$\text{原式}=\sum_{T=1}^nT^2f(T)S(\left\lfloor{\frac{n}{T}}\right\rfloor)S(\left\lfloor{\frac{m}{T}}\right\rfloor)$$ 我们通过一些手段,式子到这里就可以数论分块了,所以我们的目的就是把 $f$ 函数线性筛。 若 $\exists p \in \mathbb{P}\ s.t.\ p^3\mid n$,那么 $\mu(p)$ 和 $\mu(\dfrac{n}{d})$ 中必有一个为 $0$,那一项就不用看了。 于是我们只要考虑 $f(1)$,$f(p)$,$f(p^2)$ 就行。 $$f(1)=1$$ $$f(p)=1\mu^2(1)\mu(p)+p\mu^2(p)\mu(1)=p-1$$ $$f(p^2)=1\mu^2(1)\mu(p^2)+p\mu^2(p)\mu(p)+p^2\mu^2(p^2)\mu(1)=-p$$ 可以线性筛了。 over,时间复杂度为 $O(N + T\sqrt{N})$。 --- ### $Code:$ ```cpp #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <queue> #include <vector> #include <cmath> using namespace std; #define ll long long #define fi first #define se second #define x1 x_csyakioi_1 #define x2 x_csyakioi_2 #define y1 y_csyakioi_1 #define y2 y_csyakioi_2 #define y0 y_csyakioi_0 #define dingyi int mid = l + r >> 1, ls = p << 1, rs = p << 1 | 1; inline int read(){ int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ x = x * 10 + (ch ^ 48); ch = getchar(); } return x * f; } const int N = 1000010, mod = 1000000007; int t, n, m, pri[N], len, f[N]; bool vis[N]; inline void sieve(int n){ f[1] = 1; for(int i = 2; i <= n; ++i){ if(!vis[i]) pri[++len] = i, f[i] = i - 1; for(int j = 1; j <= len && i * pri[j] <= n; ++j){ int k = i * pri[j]; vis[k] = 1; if(i % pri[j] == 0){ if((i / pri[j]) % pri[j] != 0) f[k] = 1ll * f[i / pri[j]] * (mod - pri[j]) % mod; else f[k] = 0; break; } f[k] = 1ll * f[i] * f[pri[j]] % mod; } } for(int i = 1; i <= n; ++i) f[i] = (f[i - 1] + 1ll * f[i] * i % mod * i % mod) % mod; } inline int sum1(int x){ return 1ll * x * (x + 1) / 2 % mod; } inline void work(){ n = read(); m = read(); if(n > m) swap(n, m); int ans = 0; for(int i = 1, j; i <= n; i = j + 1){ j = min(n / (n / i), m / (m / i)); ans = (ans + 1ll * (f[j] - f[i - 1] + mod) % mod * sum1(n / i) % mod * sum1(m / i) % mod) % mod; } printf("%d\n", ans); } int main(){ t = read(); sieve(N - 10); while(t--) work(); return 0; } ```