BZOJ 2301 Problem B(莫比乌斯反演)
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一样了
1 #include<algorithm> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<iostream> 6 int mul[200005],p[200005],mark[200005],sum[200005]; 7 int read(){ 8 char ch=getchar();int t=0,f=1; 9 while (ch<'0'||ch>'9'){if (ch=='0') f=-1;ch=getchar();} 10 while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();} 11 return t*f; 12 } 13 void init(){ 14 mul[1]=1; 15 for (int i=2;i<=50000;i++){ 16 if (!mark[i]){ 17 p[++p[0]]=i; 18 mul[i]=-1; 19 } 20 for (int j=1;j<=p[0]&&p[j]*i<=50000;j++){ 21 mark[i*p[j]]=1; 22 if (i%p[j]) mul[p[j]*i]=mul[i]*(-1); 23 else{ 24 mul[p[j]*i]=0; 25 break; 26 } 27 } 28 } 29 sum[0]=0; 30 for (int i=1;i<=50000;i++) sum[i]=sum[i-1]+mul[i]; 31 } 32 int cal(int a,int b){ 33 if (a>b) std::swap(a,b); 34 int res=0; 35 for (int i=1,j;i<=a;i=j+1){ 36 j=std::min(a/(a/i),b/(b/i)); 37 res+=(a/i)*(b/i)*(sum[j]-sum[i-1]); 38 } 39 return res; 40 } 41 int main(){ 42 int T=read(); 43 init(); 44 while (T--){ 45 int a=read(),b=read(),c=read(),d=read(),k=read(); 46 a--;c--; 47 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))); 48 } 49 }