设$f(d)=sum_{i=1}^Nsum_{j=1}^M[gcd(i,j)==d],\F(n)=sum_{n|d}f(d)=lfloor frac{N}{n} floor lfloor frac{M}{n} floor$
则$f(n)$
$=sum_{n|d}mu(frac{n}{d})F(d)$
$=sum_{n|d}mu(frac{n}{d})lfloor frac{N}{d} floor lfloor frac{M}{d} floor$
设$d=kn$
$=sum_{k=1}^{min(lfloor frac{N}{n} floor,lfloor frac{M}{n} floor)}spacemu(k)lfloor frac{N}{kn} floor lfloor frac{M}{kn} floor$
所以对$lfloor frac{N}{kn} floor lfloor frac{M}{kn} floor$整除分块,对$mu(k)$搞一个前缀和。
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<cmath> #include<cctype> #include<cstdlib> #include<vector> #include<queue> #include<map> #include<set> #define ll long long #define R register ll using namespace std; namespace Fread { static char B[1<<15],*S=B,*D=B; #define getchar() (S==D&&(D=(S=B)+fread(B,1,1<<15,stdin),S==D)?EOF:*S++) inline int g() { R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-1:fix; do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret*fix; } }using Fread::g; int n,a,b,c,d,x,cnt; int mu[50010],pri[25000]; bool v[50010]; inline void MU(int n) { mu[1]=1; for(R i=2;i<=n;++i) { if(!v[i]) pri[++cnt]=i,mu[i]=-1; for(R j=1;j<=cnt&&i*pri[j]<=n;++j) { v[i*pri[j]]=true; if(i%pri[j]==0) break; mu[i*pri[j]]=-mu[i]; } } for(R i=1;i<=n;++i) mu[i]+=mu[i-1]; } inline ll calc(int a,int b) { R ret=0; a>b?swap(a,b):void(0); for(R l=1,r;l<=a;l=r+1) { r=min(a/(a/l),b/(b/l)); ret+=(ll)(mu[r]-mu[l-1])*(a/l)*(b/l); } return ret; } signed main() { #ifdef JACK freopen("NOIPAK++.in","r",stdin); #endif MU(50000); n=g(); while(n--) { R ans=0; a=g()-1,b=g(),c=g()-1,d=g(),x=g(); printf("%lld ",calc(b/x,d/x)-calc(a/x,d/x)-calc(b/x,c/x)+calc(a/x,c/x)); } }
2019.06.09