P3455 [POI2007]ZAP-Queries 题解

题目传送门

题目大意

给出 a,b,d,求满足 gcd(i,j)=d,1ia,1jb 的有序正整数对 (i,j) 的数量。
多组数据,数据组数 t5×1041da,b5×104

题目解析

显然需要求的式子就是

i=1aj=1b[gcd(i,j)=d]

我们令 n=ad,m=bd,那么式子就等价为

i=1nj=1m[gcd(i,j)=1]

显然我们可以使用 [n=1]=ε(n)=d|nμ(d) 展开 [gcd(i,j)=1],那么式子就变成

i=1nj=1nd|gcd(i,j)μ(d)

然后是套路,改变枚举顺序,先枚举 d,就可以得到

d=1μ(d)i=1n[d|i]j=1m[d|j]

这其实就是

d=1min(n,m)μ(d)ndmd

这样只需要预处理出莫比乌斯函数,使用整除分块就可以解决了。(记得开 long long
核心代码:

#define N 50000
#define maxn 50039
int pr[maxn],isp[maxn],cnt; ll mu[maxn];
void init(){
int i,j; mu[1]=1; cnt=0; isp[1]=1; for(i=2;i<=N;i++){
if(!isp[i]) pr[++cnt]=i,mu[i]=-1;
for(j=1;j<=cnt&&i*pr[j]<=N;j++){
isp[i*pr[j]]=1; mu[i*pr[j]]=-mu[i];
if(i%pr[j]==0){ mu[i*pr[j]]=0; break; }
}
} for(i=2;i<=N;i++) mu[i]+=mu[i-1]; return;
}
ll js(int n,int m){
ll i=1,r,nn=mmin(n,m),ans=0;
while(i<=nn){
r=mmin(n/(n/i),m/(m/i));
ans+=(mu[r]-mu[i-1])*(n/i)*(m/i); i=r+1;
} return ans;
}
int main(){
init(); int T; ll a,b,d; T=read();
while(T--){ a=read(); b=read(); d=read(); print(js(a/d,b/d)),pc('\n'); }
return 0;
}
posted @   jiangtaizhe001  阅读(41)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示