题解
和前一道模板题类似,先设 (f(d)),再得 (F(n)),然后反演 (f(n))。因为最终答案:
[Ans=sum_{nin prime}f(n)=sum_{nin prime}sum_{t=1}^{iglfloorfrac{N}{n}ig
floor}mu(t)igglfloorfrac{N}{nt}igg
floorigglfloorfrac{M}{nt}igg
floor
]
还可以继续处理,但这里我还有点想不明白,可以先枚举 (T=nt):
[Ans=sum_{T=1}^{N}igglfloorfrac{N}{T}igg
floorigglfloorfrac{M}{T}igg
floorsum_{n|T,nin prime}mu(frac{T}{n})
]
后面那一坨就可以在求 (mu) 之后处理出来,然后算 (Ans),就与前一道模板题差不多了,预处理后面那一坨得前缀和,然后每次询问用整除分块计算。
代码
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
using namespace std;
typedef long long LL;
const int N=1e7+10;
int n,m,vis[N],prime[N],cnt,mu[N];
LL sum[N];
void euler(int n){
mu[1]=1;
for(int i=2;i<=n;i++){
if(!vis[i]) {prime[++cnt]=i;mu[i]=-1;}
for(int j=1;1ll*i*prime[j]<=n;j++){
vis[i*prime[j]]=1;
if(i%prime[j]==0) {mu[i*prime[j]]=0;break;}
mu[i*prime[j]]=-mu[i];
}
}
for(int i=1;i<=cnt;i++)
for(int j=1;1ll*j*prime[i]<=n;j++)
sum[j*prime[i]]+=mu[j];
for(int i=1;i<=n;i++) sum[i]+=sum[i-1];
}
int main(){
euler(1e7);
int T;scanf("%d",&T);
while(T--){
LL ans=0;
scanf("%d%d",&n,&m);
if(n>m) swap(n,m);
for(int l=1,r;l<=n;l=r+1){
r=min(n/(n/l),m/(m/l));
ans+=1ll*(sum[r]-sum[l-1])*(n/l)*(m/l);
}
printf("%lld
",ans);
}
return 0;
}