[莫比乌斯反演][整除分块] Bzoj P2301 Problem b
题目描述
对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数。
题解
代码
1 #include <cstdio> 2 #include <iostream> 3 #define N 60010 4 #define ll long long 5 using namespace std; 6 ll n,k,mobius[N],p[N],bz[N],s[N]; 7 void read(ll &x) 8 { 9 x=0; ll p=1; 10 static char c;c=getchar(); 11 while (!isdigit(c)){if(c=='-')p=-1;c=getchar();} 12 while (isdigit(c)) {x=(x<<1)+(x<<3)+(c-48);c=getchar();} 13 x*=p; 14 } 15 ll calc(ll x,ll y) 16 { 17 ll r=min(x,y),ans=0; 18 for (ll a=1,b;a<=r;a=b+1) b=min(x/(x/a),y/(y/a)),ans+=((x/(a*k))*(y/(a*k))*(s[b]-s[a-1])); 19 return ans; 20 } 21 int main() 22 { 23 read(n),mobius[1]=1; 24 for (ll i=2;i<=N;i++) 25 { 26 if (!bz[i]) mobius[i]=-1,p[++p[0]]=i; 27 for (ll j=1;j<=p[0]&&i*p[j]<=N;j++) 28 { 29 bz[i*p[j]]=1; 30 if (i%p[j]==0) break; else mobius[i*p[j]]=-mobius[i]; 31 } 32 } 33 for (ll i=1;i<=N;i++) s[i]=s[i-1]+mobius[i]; 34 for (ll a,b,c,d,k,l,r,sum;n;n--) 35 { 36 read(a),read(b),read(c),read(d),read(k); 37 a=(a-1)/k,b=b/k,c=(c-1)/k,d=d/k,l=1,sum=0; 38 if (a>c) swap(a,c),swap(b,d); 39 for (ll A,B,C,D;l<=a;l=r+1) A=a/(a/l),B=b/(b/l),C=c/(c/l),D=d/(d/l),r=min(A,min(B,min(C,D))),sum+=(s[r]-s[l-1])*(b/l-a/l)*(d/l-c/l); 40 for (ll A,B,C,D;l<=min(b,c);l=r+1) B=b/(b/l),C=c/(c/l),D=d/(d/l),r=min(B,min(C,D)),sum+=(s[r]-s[l-1])*(b/l)*(d/l-c/l); 41 for (ll A,B,C,D;l<=min(b,d);l=r+1) B=b/(b/l),D=d/(d/l),r=min(B,D),sum+=(s[r]-s[l-1])*(b/l)*(d/l); 42 printf("%lld\n",sum); 43 } 44 }