题目大意:求 \[\sum\limits_{i=1}^a\sum\limits_{j=1}^b[gcd(i,j)=c]\]
题解:学会了狄利克雷卷积。
\[\epsilon=\mu \ast 1\]
将艾弗森表达式转化成卷积的形式,在调换求和顺序,消去不必要的和式。最后利用除法分块+预处理的莫比乌斯函数前缀和在 \(O(\sqrt n)\) 时间内单次回答询问。
代码如下
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e4+10;
int mu[maxn],sum[maxn],prime[maxn],tot;
bool vis[maxn];
void seive(){
mu[1]=1,vis[1]=1;
for(int i=2;i<=5e4;i++){
if(!vis[i])prime[++tot]=i,mu[i]=-1;
for(int j=1;i*prime[j]<=5e4;j++){
vis[i*prime[j]]=1;
if(i%prime[j]==0)break;
mu[i*prime[j]]=-mu[i];
}
}
for(int i=1;i<=5e4;i++)sum[i]=sum[i-1]+mu[i];
}
ll calc(ll a,ll b){
if(a>b)swap(a,b);
ll ans=0;
for(int i=1;i<=a;i++){
int j=min(a/(a/i),b/(b/i));
ans+=(ll)(sum[j]-sum[i-1])*(ll)(a/i)*(ll)(b/i);
i=j;
}
return ans;
}
int main(){
seive();
int T;scanf("%d",&T);
while(T--){
int a,b,d;
scanf("%d%d%d",&a,&b,&d);
printf("%lld\n",calc(a/d,b/d));
}
return 0;
}