简要题意:
求
\[\sum_{i=a}^b \sum_{j=c}^d [\gcd(i,j)==k] \]
共 \(T\) 组询问.
本题没有部分分,直接考虑一个式子:
\[\sum_{i=1}^a \sum_{j=1}^b [\gcd(i,j)==k] \]
\[= \sum_{i=1}^{\lfloor \frac{a}{k} \rfloor} \sum_{j=1}^{\lfloor \frac{b}{k} \rfloor} [\gcd(i,j)==1] \]
\[= \sum_{i=1}^{\lfloor \frac{a}{k} \rfloor} \sum_{j=1}^{\lfloor \frac{b}{k} \rfloor} \sum_{d | \gcd(i,j)} \mu_d \]
\[= \sum_{d=1}^{\min(a,b)} \mu_d \lfloor \frac{a}{dk} \rfloor \lfloor \frac{b}{dk} \rfloor \]
上面每一步都是在用 莫比乌斯反演 的性质,不加解释。
那么,我们只需要用 \(O(n)\) 的时间预处理 \(\mu\),就可以用 整除分块 在 \(O(\sqrt{\min(a,b)})\) 的时间内求解这样一个式子。
那么,已知 \(k\),令:
\[f_{a,b} = \sum_{i=1}^a \sum_{j=1}^b [\gcd(i,j)==k] \]
则:
\[\sum_{i=a}^b \sum_{j=c}^d [\gcd(i,j)==k] = f_{b,d} - f_{b,c-1} - f_{a-1,d} + f_{a-1,c-1} \]
(可以稍微参考一下二维前缀和得出)
所以我们以 \(O(5 \times 10^4)\) 预处理,\(O(n \sqrt{\min(a,b)})\) 询问解决了本题。
时间复杂度:\(O(a + n\sqrt{a})\).
实际得分:\(100pts\).(需要适度卡常)
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+1;
inline ll read(){char ch=getchar(); ll f=1; while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
ll x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}
int prime[N],mu[N],sum[N];
int cnt=0,k; bool h[N];
inline void Euler(int n) {
mu[1]=1; for(register int i=2;i<=n;i++) {
if(!h[i]) mu[i]=-1,prime[++cnt]=i;
for(int j=1;j<=cnt && i*prime[j]<=n;j++) {
h[i*prime[j]]=1;
if(i%prime[j]==0) break;
mu[i*prime[j]]-=mu[i];
}
} for(int i=1;i<=n;i++) sum[i]=sum[i-1]+mu[i];
} //预处理 mu 的前缀和
inline int min(int a,int b) {return a<b?a:b;}
inline ll calc(int a,int b) {
ll ans=0;
for(register int i=1;i<=min(a,b);) {
int t=min(a/(a/i),b/(b/i));
ans+=1ll*(a/k/i)*(b/k/i)*(sum[t]-sum[i-1]);
i=t+1;
} return ans; //整除分块
}
int main() {
Euler(N-1); int T=read(); while(T--) {
int a=read(),b=read(),c=read(),d=read(); k=read();
printf("%lld\n",calc(b,d)-calc(b,c-1)-calc(a-1,d)+calc(a-1,c-1));
}
return 0;
}