luogu-P2257-YY的gcd
题意
直接看题面吧 luogu P2257
思路
莫比乌斯反演(虽然本质上是容斥,在这里推公式更好做,但有时候容斥更好想)
\[\begin{aligned}
(p \in &\ prime)\\
Ans &=\sum _p \sum_{i=1}^N \sum_{i=1}^M [gcd(i,j)==p] \\
&= \sum _p \sum_{i=1}^{\lfloor \frac{N}{p}\rfloor} \sum_{j=1}^{\lfloor \frac{M}{p}\rfloor} [gcd(i,j)=1] \\
&= \sum _p \sum _{k=1} ^{min(\lfloor \frac{N}{p}\rfloor,\lfloor \frac{M}{p}\rfloor)} \mu(k) \cdot \lfloor \frac{\lfloor \frac{N}{p}\rfloor}{k}\rfloor \cdot \lfloor \frac{\lfloor \frac{M}{p}\rfloor}{k}\rfloor \\
&= \sum _p \sum _{k=1} ^{min(\lfloor \frac{N}{p}\rfloor,\lfloor \frac{M}{p}\rfloor)} \mu(k) \cdot \lfloor \frac{N}{p\cdot k}\rfloor \cdot \lfloor \frac{M}{p\cdot k}\rfloor \\
(&T=k\cdot p) \\
&= \sum _p \sum _{T=1} ^{min(N,M)} [p|T]\cdot \mu(\frac{T}{p}) \cdot \lfloor \frac{N}{T}\rfloor \cdot \lfloor \frac{M}{T}\rfloor \\
&=\sum _{T=1} ^{min(N,M)} \lfloor \frac{N}{T}\rfloor \cdot \lfloor \frac{M}{T}\rfloor \sum _p [p|T]\cdot \mu(\frac{T}{p}) \\
&=\sum _{T=1} ^{min(N,M)} \lfloor \frac{N}{T}\rfloor \cdot \lfloor \frac{M}{T}\rfloor \sum _{p\in Prime,p|T} \mu(\frac{T}{p})
\end{aligned}
\]
考虑预处理\(\sum _{p\in Prime,p|T} \mu(\frac{T}{p})\),然后就能\(O(max(N,M))\)算,再数论分块就能达到\(O(\sqrt{max(N,M)})\)
记\(F(T)=\sum _{p\in Prime,p|T} \mu(\frac{T}{p})\),由于\(10^7\)内质数个数约为7e5个,我们可以枚举质数在\(O(nlog\ n)\)跑出每个质数对不同F(T)的贡献并叠加
代码
代码中由于个人习惯问题\(\mu(1) = -1\),其他都一样
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
const int MX = 1e7+6;
int mob[MX] = {0};
bool notP[MX] = {false};
int prms[MX];
int prm=0;
int T[MX] = {0};
int sumT[MX];
void get_mob() { // pre process
mob[1] = -1; // <-- you can make it 1, and make mob[prime]=-1
for(int i=2;i<MX;++i) {
if(!notP[i]) {
prms[prm] = i; // get prime
++prm;
mob[i] = 1; // get mob
}
for(int j=0;j<prm;++j) {
if(i*prms[j]>=MX) break;
mob[i*prms[j]] = -mob[i];
notP[i*prms[j]] = true;
if(i%prms[j]==0) {
mob[i*prms[j]] = 0;
break;
}
}
}
for(int i=0;i<prm;++i) { // get F(T)
for(int j=1;j*prms[i]<MX;++j) {
T[j*prms[i]] += mob[j];
}
}
sumT[0] = T[0];
for(int i=1;i<MX;++i) {
sumT[i] = sumT[i-1] + T[i];
}
}
int main(int argc, char const *argv[])
{
std::ios_base::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);
get_mob();
int t;
cin >> t;
while(t--) {
i64 N,M;
cin >> N >> M;
i64 ans=0;
if(N>M) swap(N,M);
for(i64 l=1,r;l<=N;l=r+1) {
r = min(N/(N/l),M/(M/l));
r = min(r,N);
ans += (N/l) * (M/l) * (sumT[r]-sumT[l-1]);
}
cout << -ans << '\n';
}
return 0;
}
Living with bustle, hearing of isolation.