先尝试化一下题目给的式子
∑ni=1∑mj=1f(gcd(i,j))−>
∑df(d)∑⌊n/d⌋i=1∑⌊m/d⌋j=1,gcd(i,j)=11 −>
∑Df(D)∑dμ(d)∑⌊n/Dd⌋i=1∑⌊m/Dd⌋j=1−>
∑K∑d|Kf(Kd)μ(d)⌊nK⌋⌊mK⌋
设
g=f∗μ−>
∑Kg(K)⌊nK⌋⌊mK⌋
我们将它化成了卷积,但是f不是个积性函数,不能直接筛,所以考虑
μ
的一些性质
首先如果
当
d
不含平方因子时,
当其是最大次幂-1时,K的最高次幂质因子d全部要含,
设K含m个最高次幂质因子,其他还有k个质因子,
基于
μ
的定义和性质,对答案的贡献是
而 ∑ki=0Cik×(−1)i 在k≠0时是=0的
于是再分情况,先讨论k≠0的情况
那么当 f(Kd) 为最大次幂-1时,贡献为0
当其不为最大次幂-1时,不好算方案,所以用总方案的 μ -其为最大次幂-1的
当k=0时,即K的所有质因子指数相同,
当m为奇数时,推理同上,总贡献为 −(f(K)−1)+f(K)=1
当m为偶数时,推理同上,总贡献为 (f(K)−1)−f(K)=−1
于是我们就得到了一种线性筛 g 的方法,再维护一下
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn = 10000001;
int p[maxn],pr,mpn[maxn],dto[maxn];
int num[maxn];
int H[maxn];
bool v[maxn],jud[maxn];
int prepare()
{
H[1]=0;
for(int i=2;i<maxn;i++)
{
if(!v[i])
{
p[++pr]=i;
mpn[i]=1; dto[i]=1;
num[i]=1;
jud[i]=true;
}
if((jud[dto[i]]&&mpn[dto[i]]==mpn[i])||dto[i]==1) jud[i]=true;
if(jud[i])
{
if(num[i]&1) H[i]=1;
else H[i]=-1;
}
for(int j=1;j<=pr&&p[j]*i<maxn;j++)
{
int k=p[j]*i;
v[k]=true;
if(i%p[j]==0)
{
mpn[k]=mpn[i]+1;
dto[k]=dto[i];
num[k]=num[i];
break;
}
mpn[k]=1;
dto[k]=i;
num[k]=num[i]+1;
}
H[i]+=H[i-1];
}
}
int main()
{
prepare();
int t; scanf("%d",&t);
while(t--)
{
ll n,m; scanf("%lld%lld",&n,&m);
ll l=1,r=min(n,m);
ll ret=0;
while(l<=r)
{
ll nex=min(n/(n/l),m/(m/l));
ret += (n/l)*(m/l)*(ll)(H[nex]-H[l-1]);
l=nex+1;
}
printf("%lld\n",ret);
}
return 0;
}