题意:求$\sum_{i=a}^{b}\sum_{j=c}^{d}[gcd(i,j)==k]$(1<=a,b,c,d,k<=50000)。
是洛谷P3455 [POI2007]ZAP-Queries加强版,多了下界。
设$f(n,m)=\sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)==k]$
根据容斥可以显然的得出Ans=f(b,d)-f(b,c-1)-f(a-1,d)+f(a-1,c-1)。
对于f(n,m)的求解:
$f(n,m)=\sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)==k]$
$=\sum_{i=1}^{\lfloor \frac{n}{k}\rfloor}\sum_{j=1}^{\lfloor \frac{m}{k}\rfloor}[gcd(i,j)==1]$
$=\sum_{d=1}^{\lfloor \frac{n}{k}\rfloor}\mu(d){\lfloor \frac{n}{kd}\rfloor}{\lfloor \frac{m}{kd}\rfloor}$
预处理莫比乌斯函数前缀和,后面整除分块。
#include <bits/stdc++.h> #define ll long long using namespace std; const int N=50005; bool p[N]; int pri[N],tot,mu[N]; void init() { mu[1]=1; for(int i=2;i<N;i++) { if(!p[i]) pri[tot++]=i,mu[i]=-1; for(int j=0;j<tot&&pri[j]*i<N;j++) { p[pri[j]*i]=true; if(i%pri[j]==0) { mu[i*pri[j]]=0; break; } else mu[i*pri[j]]=-mu[i]; } } for(int i=1;i<N;i++) mu[i]+=mu[i-1]; } ll cal(int n,int m,int k) { if(n>m) swap(n,m); ll ans=0; for(int l=1,r;l<=n;l=r+1) { r=min(n/(n/l),m/(m/l)); ans+=1LL*(mu[r]-mu[l-1])*(n/k/l)*(m/k/l); } return ans; } int main() { init(); int T,a,b,c,d,k; scanf("%d",&T); while(T--) { scanf("%d%d%d%d%d",&a,&b,&c,&d,&k); printf("%lld\n",cal(b,d,k)-cal(b,c-1,k)-cal(a-1,d,k)+cal(a-1,c-1,k)); } return 0; }