求gcd(i,j)为质数的个数。即
∑p∑i=1n∑j=1mgcd(i,j)==p
首先我们可以像bzoj2301一样把后一部分化简,得到(假定n< m)
∑p∑d=1⌊n/p⌋μ(d)⌊n/pd⌋⌊m/pd⌋
设k=pd,则得到
∑k=1n∑p|kμ(k/p)⌊n/k⌋⌊m/k⌋
我们预处理出前半部分的前缀和(利用线性素数筛),后面的就是用floor函数分块的套路算啦!素数是O(n/logn)级别的,更新时是均摊O(logn)的,因此预处理的复杂度是O(n)的。总的复杂度是
O(T∗(√n))
。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define N 10000010
int T,n,m,mu[N],prime[N],tot=0;
ll f[N];
bool notprime[N];
inline int read(){
int x=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
void Mobius(){
memset(notprime,0,sizeof(notprime));
mu[1]=1;notprime[1]=1;
for(int i=2;i<=N;++i){
if(!notprime[i]){
prime[++tot]=i;mu[i]=-1;
}
for(int j=1;prime[j]*i<=N;++j){
notprime[prime[j]*i]=1;
if(i%prime[j]==0){
mu[prime[j]*i]=0;break;
}
mu[prime[j]*i]=-mu[i];
}
}
for(int j=1;j<=tot;++j)
for(int i=1;prime[j]*i<=N;++i)
f[prime[j]*i]+=mu[i];
for(int i=2;i<=N;++i) f[i]+=f[i-1];
}
ll ANS(int a,int b){
ll re=0;if(a>b) swap(a,b);
int last;
for(int i=1;i<=a;i=last+1){
last=min(a/(a/i),b/(b/i));
re+=(f[last]-f[i-1])*(a/i)*(b/i);
}
return re;
}
int main(){
// freopen("a.in","r",stdin);
Mobius();
T=read();
while(T--){
n=read();m=read();
printf("%lld\n",ANS(n,m));
}
return 0;
}