您的位置:首页 > 其它

BZOJ 1101 Zap(莫比乌斯反演)

2016-06-14 10:59 260 查看
http://www.lydsy.com/JudgeOnline/problem.php?id=1101

给定a,b,d,求有多少gcd(x,y)==d(1<=x<=a&&1<=y<=b)

思路:

Σgcd(x,y)==d (1<=x<=a,1<=y<=b)

=

Σgcd(x,y)==1 (1<=x<=a/d,1<=y<=b/d)

令G(i)=num(i|gcd(x,y))=n/i*m/i

g(i)=num(i=gcd(x,y))

g(i)=ΣG(d)*u(d/i) (i|d)

则答案就是g(1)

g(1)=ΣG(i)*u(i) (1<=i<=min(n,m))

=Σ(n/i)*(m/i)*u(i)

因此做出u(i)的前缀和,这样就可以一起处理n/i和m/i相同的i

#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
int mul[200005],mark[200005],sum[200005],p[200005];
int read(){
char ch=getchar();int t=0,f=1;
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();}
return t*f;
}
void init(){
mul[1]=1;
for (int i=2;i<=50000;i++){
if (!mark[i]){
p[++p[0]]=i;
mul[i]=-1;
}
for (int j=1;j<=p[0]&&i*p[j]<=50000;j++){
mark[p[j]*i]=1;
if (i%p[j]) mul[p[j]*i]=mul[i]*(-1);
else {
mul[p[j]*i]=0;
break;
}
}
}
sum[0]=0;
for (int i=1;i<=50000;i++)
sum[i]=sum[i-1]+mul[i];
}
int cal(int a,int b){
if (a>b) std::swap(a,b);
int res=0,n=a,m=b;
for (int i=1,j;i<=a;i=j+1){
j=std::min(n/(n/i),m/(m/i));
res+=(a/i)*(b/i)*(sum[j]-sum[i-1]);
}
return res;
}
int main(){
int Q=read();
init();
while (Q--){
int a=read(),b=read(),d=read();
printf("%d\n",cal(a/d,b/d));
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: