[BZOJ 2820] YY of gcd (+ Mobius inversion block number theory)
Face questions
Given N, M, ask \ (1 \ leq x \ leq N, 1 \ leq y \ leq M \) and gcd (x, y) is the number of primes (x, y). q group inquiry
analysis
All we ask is
\ [\ sum_ {P \ P} in \ sum_. 1} ^ {n-I = \ sum_. 1} = {J ^ m [GCD (I, J) = P] \] (uppercase P represents a set of prime numbers)
The \ (kgcd (I, J) = GCD (Ki, kJ) \) ,
\[原式=\sum_{p \in P} \sum_{i=1}^{\lfloor n/p \rfloor} \sum_{j=1}^{\lfloor m/p \rfloor} [gcd(i,j)=1]\]
According to a further conclusion Möbius inversion in the usual (see proof BZOJ 2301 ) \ [\ sum_. 1} ^ {n-I = \ sum_. 1} = {J ^ m [GCD (I, J) =. 1] = \ sum_ {d = 1} ^ {min (n, m)} \ mu (d) \ lfloor \ frac {n} {d} \ rfloor \ lfloor \ frac {m} {d} \ rfloor \]
\[原式=\sum_{p \in P} \sum_{d=1}^{min( \lfloor n/p \rfloor, \lfloor m/p \rfloor)} \mu(d) \lfloor \frac{n}{pd} \rfloor \lfloor \frac{m}{pd} \rfloor \]
Order \ (T = PD \) , then \ (d = \ frac {T } {p} \)
Changing the order of summation, \ [original formula = \ sum_ {T = 1} ^ {min (n, m)} \ sum_ {p | t \ \ cap \ p \ in P} \ lfloor \ frac {n} {T } \ rfloor \ lfloor \ frac { m} {T} \ rfloor \ mu (\ frac {T} {p}) \]
\[=\sum_{T=1}^{min(n,m)}) \lfloor \frac{n}{T} \rfloor \lfloor \frac{m}{T} \rfloor \sum_{p|t \ \cap \ p \in P} \mu(\frac{T}{p})\]
令\(g(n)=\sum_{p|n \ \cap \ p \in P } \mu(\frac{n}{p})\)
\[原式=\sum_{T=1}^{min(n,m)}) \lfloor \frac{n}{T} \rfloor \lfloor \frac{m}{T} \rfloor g(T)\]
The front part of number theory can solve the block, considering how quickly obtain \ (g (T) \)
For each prime number \ (the p-\) , we start from the 1 enum \ (J \) , and ensure that \ (jp \ the n-Leq \) , followed by \ (\ mu (j) \ ) update \ (g (jp ) \) values.
Because of \ (. 1 /. 1. 1 + / 2 +. 1 /. 3. 1 + ... + / n-= O (logN) \) , each update complexity is amortized \ (O (\ log n) \) , and 1 ~ n and prime with a probability of about \ (\ frac {n} { \ ln n} \) th, the pre-function g total time complexity is \ (O (n) \)
The total time complexity \ (O (n + q \ sqrt n) \)
Code
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 10000000
using namespace std;
typedef long long ll;
int t,n,m;
int cnt;
int prime[maxn+5];
bool vis[maxn+5];
int mu[maxn+5];
ll g[maxn+5];
ll sumg[maxn+5];
void sieve(int n){
mu[1]=1;
for(int i=2;i<=n;i++){
if(!vis[i]){
mu[i]=-1;
prime[++cnt]=i;
}
for(int j=1;j<=cnt&&i*prime[j]<=n;j++){
vis[i*prime[j]]=1;
if(i%prime[j]==0){
mu[i*prime[j]]=0;
break;
}else mu[i*prime[j]]=-mu[i];
}
}
for(int i=1;i<=cnt;i++){
for(int j=1;j*prime[i]<=n;j++){
g[prime[i]*j]+=mu[j];
}
}
for(int i=1;i<=n;i++){
sumg[i]=sumg[i-1]+g[i];
}
}
int cas;
ll calc(int n,int m){
int nn=min(n,m);
ll ans=0;
for(int l=1,r;l<=nn;l=r+1){
r=min(n/(n/l),m/(m/l));
ans+=(sumg[r]-sumg[l-1])*(n/l)*(m/l);
}
return ans;
}
int main(){
sieve(maxn);
scanf("%d",&cas);
while(cas--){
scanf("%d %d",&n,&m);
printf("%lld\n",calc(n,m));
}
}