题意:
k次询问,每次询问
∑ni=1∑mj=1gcd(i,j)==d
∑
i
=
1
n
∑
j
=
1
m
g
c
d
(
i
,
j
)
==
d
,即gcd(i,j)结果为d的个数。
k,n,m≤5e5。
题解:
原式显然可以化简为
∑Ni=1∑Mj=1gcd(i,j)==1
∑
i
=
1
N
∑
j
=
1
M
g
c
d
(
i
,
j
)
==
1
,其中
N=⌊nd⌋,M=⌊md⌋
N
=
⌊
n
d
⌋
,
M
=
⌊
m
d
⌋
。
由于莫比乌斯函数有一个性质:
n=1时,显然原式值为1;
n≠1时,设 d=∏k1piai d = ∏ 1 k p i a i ,p为质数,a≠0,讨论每个d对答案的贡献。
- ∃ai≥2 ∃ a i ≥ 2 ,d对答案的贡献=0;
- ∀ai=1 ∀ a i = 1 ,d对答案的贡献= (k0)−(k1)+(k2)−(k3)+… ( k 0 ) − ( k 1 ) + ( k 2 ) − ( k 3 ) + …
根据二项式定理,当d不为1时对答案的贡献均为0,所以性质得证。
所以原式即可化为
优先枚举d的取值,考虑 d∣gcd(i,j) d ∣ g c d ( i , j ) ,可得 (d∣i)∧(d∣j) ( d ∣ i ) ∧ ( d ∣ j ) ;
即 μ(d) μ ( d ) 被统计进答案,当且仅当 i,j i , j 均为 d d 的整数倍
所以答案为
由于 ⌊Nd⌋ ⌊ N d ⌋ , ⌊Md⌋ ⌊ M d ⌋ 取值的阶梯性,我们可以在 O(n−−√) O ( n ) 的时间复杂度下枚举 ⌊Nd⌋ ⌊ N d ⌋ , ⌊Md⌋ ⌊ M d ⌋ 的不同取值。
总时间复杂度 O(nn−−√) O ( n n ) 。
#include<cstdio>
#include<algorithm>
#define N 55000
#define mx 50000
using namespace std;
int mobius[N],prime[N],flag[N],tot=0,sum[N];
void sol(){
mobius[1]=1;
for(int i=2;i<=mx;i++){
if(!flag[i]){prime[tot++]=i;mobius[i]=-1;}
for(int j=0;j<tot;j++){
if(prime[j]*i>50000)break;
flag[prime[j]*i]=true;
if(i%prime[j]==0){mobius[prime[j]*i]=0;break;}
else mobius[prime[j]*i]=-mobius[i];
}
}
for(int i=1;i<=mx;i++)sum[i]=mobius[i]+sum[i-1];
return;
}
int main(){
int n;
scanf("%d",&n);
sol();
while(n--){
int n,m,d;
scanf("%d%d%d",&n,&m,&d);
n/=d,m/=d;
//sigma(mobius(d)*(n/d)*(m/d))
int ans=0,t;
for(int i=1;(n/i)&&(m/i);i=t+1){
t=min(n/(n/i),m/(m/i));
ans+=(sum[t]-sum[i-1])*(n/i)*(m/i);
}
printf("%d\n",ans);
}
}