大致题意:给你两个数字n和m,让你求,其中f(i,j)表示gcd(i,j)是否为完全平方数,如果是则f(i,j)==0,否则为f(i,j)==1。
首先,有了之前 BZOJ 2301 的经验,这道题目可以比较简单的讲。BZOJ 2301 这题是求一定范围内的两个数字gcd为1的组数。这题我直接在那个的基础上面讲。
根据之前莫比乌斯反演的结果:
到这道题的话,最后结果就是:
考虑交换求和次序:
到目前为止,我们这个式子即使用上分块求和优化,它的的复杂度是的,注意到本题N可以到1e7这大,然后T也有1e4这么多组,因此到这一步是远远不够的。对于右边这个求和式子,我们考虑它的性质。我们不妨令。分情况考虑:
当d为质数的时候,要满足x^2|d只有当x为1的时候,因此此时T(d)=(d)。
当d%p!=0的时候,这个p表示某一个质数。此时我们可以考虑利用莫比乌斯函数的积性:
当d%p==0的时候。表明d已经可以被p分解,那么d*p一定可以被p分解两次以上,因此T(d*p)的x的取值会比T(d)多一个p*p,那么有: ,注意到右边的和式的x取值不会到p,那么意味着也能被p分解两次,即对应分解质因数p的指数大于1。根据莫比乌斯函数的定义,只要(x)种出现一个质因子的指数大于1,那么(x)=0。因此右边那一项等于0。
由此我么们可以写出T(d)的表达式:
经过整理,我们发现,T本身就可以看作莫比乌斯函数的变种,因此我可以直接用T自己的表达式:
这样我们就可以在预处理的时候,仿照线性筛素数和莫比乌斯函数的方法,O(N)的求出T(d)。然后再对这个T(d)进行求和,仿照BZOJ 2301 的方法进行分块求和优化,这样询问一次的复杂度就是。总的时间复杂度就是。具体见代码:
#include<bits/stdc++.h>
#define IO ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define LL long long
#define N 10000010
using namespace std;
int s[N],p[N],T[N];
bool isp[N];
void init()
{
int sz=0;
s[1]=T[1]=1;
for(int i=2;i<N;i++)
{
if(!isp[i]) p[++sz]=i,T[i]=-1;
for(int j=1;j<=sz&&i*p[j]<N;j++)
{
isp[i*p[j]]=1;
if(i%p[j]==0)
{
T[p[j]*i]=T[i/p[j]];
break;
} else T[p[j]*i]=-T[i];
}
s[i]=s[i-1]+T[i];
}
}
LL cal(int n,int m)
{
LL res=0,last;
for(int i=1;i<=n&&i<=m;i=last+1)
{
last=min(n/(n/i),m/(m/i));
res+=1LL*(s[last]-s[i-1])*(n/i)*(m/i);
}
return res;
}
int main()
{
int b,d,n;
IO; init(); cin>>n;
while(n--)
{
cin>>b>>d;
cout<<(LL)b*d-cal(b,d)<<endl;
}
return 0;
}