您的位置:首页 > 其它

BZOJ 2301 Problem B(莫比乌斯反演)

2016-06-14 11:19 330 查看
http://www.lydsy.com/JudgeOnline/problem.php?id=2301

题意:给a,b,c,d,k,求gcd(x,y)==k的个数(a<=x<=b,c<=y<=d)

思路:假设F(a,b)代表gcd(x,y)==k 的个数(1<=x<=a,1<=y<=b)

那么这是满足区间加减的

ans=F(b,d)-F(b,c)-F(a,d)+F(a,c)

剩下的就和Zap一样了

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