∑Ni=1∑Mj=1d(ij)
∑
i
=
1
N
∑
j
=
1
M
d
(
i
j
)
这个约数个数和好像是个经典套路qaq
我们分别枚举i,j的约数d1,d2,就可以计算方案数了,但要去重,因为有2*1=1*2=2这种情况,所以我们强制i的约数d1达到上限,即
(i/d1,d2)=1
(
i
/
d
1
,
d
2
)
=
1
∑d1∑d1|i∑d2∑d2|i[(i/d1,d2)=1] ∑ d 1 ∑ d 1 | i ∑ d 2 ∑ d 2 | i [ ( i / d 1 , d 2 ) = 1 ]
∑d1∑d1|i∑d2[(i/d1,d2)=1](⌊md2⌋) ∑ d 1 ∑ d 1 | i ∑ d 2 [ ( i / d 1 , d 2 ) = 1 ] ( ⌊ m d 2 ⌋ )
∑i⌊ni⌋∑j⌊mj⌋[(i,j)=1] ∑ i ⌊ n i ⌋ ∑ j ⌊ m j ⌋ [ ( i , j ) = 1 ]
然后就是个简单的反演啦,5w可以预处理
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 = 50005;
ll s[maxn];
int p[maxn],pri,mu[maxn],f[maxn];
bool v[maxn];
void pre()
{
mu[1]=1; f[1]=1;
for(int i=2;i<maxn;i++)
{
if(!v[i]) p[++pri]=i,mu[i]=-1;
for(int j=1,k=p[j]*i;k<maxn;j++,k=p[j]*i)
{
v[k]=true;
if(i%p[j]==0) { mu[k]=0; break; }
mu[k]=-mu[i];
}
f[i]=f[i-1]+mu[i];
}
for(int i=1;i<maxn;i++)
{
int l,r;
for(l=1;l<=i;l=r+1)
{
r=i/(i/l);
s[i]+=(ll)(r-l+1)*(i/l);
}
}
}
int n,m;
int main()
{
pre();
int tcase; scanf("%d",&tcase);
while(tcase--)
{
scanf("%d%d",&n,&m); if(n>m) swap(n,m);
ll ans=0;
int l,r;
for(l=1;l<=n;l=r+1)
{
r=min(n/(n/l),m/(m/l));
ans+=(ll)(f[r]-f[l-1])*s[n/l]*s[m/l];
}
printf("%lld\n",ans);
}
return 0;
}