题目看这里
又到了推式子的时候了,莫比乌斯反演入门题
∑i=1n∑j=1m[prime(i,j)]∑i=1n∑j=1m[prime(i,j)]
首先搞一个f(d)f(d)表示有多少对(i,j)的gcd就是d
那么原式=∑nd=1[prime(d)]∗f(d)=∑d=1n[prime(d)]∗f(d)
设F(x)=∑x|df(d)=[nx][mx]F(x)=∑x|df(d)=[nx][mx]
就得到原式=∑nd=1[prime(d)]∗∑iF(i∗d)∗μ(i)=∑d=1n[prime(d)]∗∑iF(i∗d)∗μ(i)
=∑i∗d<=nF(i∗d)∗μ(i)∗[prime(d)]=∑i∗d<=nF(i∗d)∗μ(i)∗[prime(d)]
=∑T<=nF(T)∗∑prime(d)=1,d|Tμ(Td)=∑T<=nF(T)∗∑prime(d)=1,d|Tμ(Td)
预处理后面那个g(T)=∑prime(d)=1,d|Tμ(Td)g(T)=∑prime(d)=1,d|Tμ(Td)就可以分块求答案了
#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 5000010
#define LL long long
using namespace std;
bool vis[N];
int mu[N],s[N],w[N>>2],t,n,m,T;
inline LL F(int d){
return (LL)(n/d)*(m/d);
}
inline void cal(){
scanf("%d%d",&n,&m);
if(n>m) swap(n,m); LL S=0;
for(int i=1,j;i<=n;i=j+1){
j=min(n/(n/i),m/(m/i));
S+=F(i)*(s[j]-s[i-1]);
}
printf("%lld\n",S);
}
int main(){
mu[1]=1;
for(int i=2;i<=5000000;++i){
if(!vis[i]) mu[w[++t]=i]=-1;
for(int j=1,k;j<=t && (k=i*w[j])<=5000000;++j){
vis[k]=1;
if(i%w[j]==0) { mu[k]=0; break; } else mu[k]=-mu[i];
}
}
for(int i=1;i<=t;++i)
for(int j=w[i],k=1;j<=5000000;++k,j+=w[i]) s[j]+=mu[k];
for(int i=1;i<=5000000;++i) s[i]+=s[i-1];
for(scanf("%d",&T);T--;cal());
}