题意:求(sum_{i=1}^{n}sum_{j=1}^{m}[gcd(i,j)==1])
(assume n<m)
(sum_{i=1}^{n}sum_{j=1}^{m}[gcd(i,j)==1])
(Longrightarrow sum_{x=1}^{n}sum_{i=1}^{n}sum_{j=1}^{m}sum_{x|gcd(i,j)}mu(x))
(Longrightarrow sum_{x=1}^{n}sum_{i=1}^{n}sum_{j=1}^{m}sum_{x|i,x|j}mu(x))
(Longrightarrow sum_{x=1}^{n}sum_{i=1}^{n}sum_{j=1}^{m}[x|i,x|j]mu(x))
(Longrightarrow sum_{x=1}^{n}sum_{i=1}^{n/x}sum_{j=1}^{m/x}mu(x))
(Longrightarrow sum_{x=1}^{n}lfloorfrac nx floorlfloorfrac mx floormu(x))
那么我们(O(n))筛出(mu(x))函数的前缀和,再用整除分块优化,最终时间复杂度为(O(Tsqrt{n}))
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1000000+10;
ll n,m,prim[maxn],vis[maxn],mu[maxn],cnt,ans;
void getmu(ll n){
register ll i,j;
mu[1]=1;
for(i=2;i<=n;i++){
if(!vis[i]){prim[++cnt]=i;mu[i]=-1;}
for(j=1;i*prim[j]<=n&&j<=cnt;j++){
vis[i*prim[j]]=1;
if(i%prim[j]==0) break;
mu[i*prim[j]]=-mu[i];
}
}
for(i=1;i<=n;i++) mu[i]+=mu[i-1];
}
int main()
{
getmu(1000000);
register ll T,l,r;
scanf("%d",&T);
while(T--){
scanf("%lld%lld",&n,&m);
if(n>m) swap(n,m);
ans=0;
for(l=1;l<=n;l=r+1){
r=min(n/(n/l),m/(m/l));
ans+=(n/l)*(m/l)*(mu[r]-mu[l-1]);
}
printf("%lld
",ans);
}
return 0;
}