前置知识:莫比乌斯反演
题解
设 f ( k ) = ∑ x = a b ∑ y = c d [ gcd ( x , y ) = k ] , F ( k ) = ∑ x = a b ∑ x = c d [ k ∣ gcd ( x , y ) ] f(k)=\sum\limits_{x=a}^b\sum\limits_{y=c}^d[\gcd(x,y)=k],F(k)=\sum\limits_{x=a}^b\sum\limits_{x=c}^d[k|\gcd(x,y)] f(k)=x=a∑by=c∑d[gcd(x,y)=k],F(k)=x=a∑bx=c∑d[k∣gcd(x,y)]
则有 F ( k ) = ∑ k ∣ n f ( n ) F(k)=\sum\limits_{k|n}f(n) F(k)=k∣n∑f(n)
由莫比乌斯反演可得
f ( k ) = ∑ k ∣ n μ ( n k ) × F ( n ) f(k)=\sum\limits_{k|n}\mu(\dfrac nk)\times F(n) f(k)=k∣n∑μ(kn)×F(n)
因为 F ( k ) = ∑ x = a b ∑ x = c d [ k ∣ gcd ( x , y ) ] = ( ⌊ b k ⌋ − ⌊ a − 1 k ⌋ ) × ( ⌊ d k ⌋ − ⌊ c − 1 k ⌋ ) F(k)=\sum\limits_{x=a}^b\sum\limits_{x=c}^d[k|\gcd(x,y)]=(\lfloor \dfrac bk \rfloor-\lfloor \dfrac{a-1}{k} \rfloor)\times (\lfloor \dfrac dk \rfloor-\lfloor \dfrac{c-1}{k} \rfloor) F(k)=x=a∑bx=c∑d[k∣gcd(x,y)]=(⌊kb⌋−⌊ka−1⌋)×(⌊kd⌋−⌊kc−1⌋)
所以 f ( k ) = ∑ k ∣ n μ ( n k ) × F ( n ) = ∑ k ∣ n μ ( n k ) × ( ⌊ b n ⌋ − ⌊ a − 1 n ⌋ ) × ( ⌊ d n ⌋ − ⌊ c − 1 n ⌋ ) f(k)=\sum\limits_{k|n}\mu(\dfrac nk)\times F(n)=\sum\limits_{k|n}\mu(\dfrac nk)\times (\lfloor \dfrac bn \rfloor-\lfloor \dfrac{a-1}{n} \rfloor)\times (\lfloor \dfrac dn \rfloor-\lfloor \dfrac{c-1}{n} \rfloor) f(k)=k∣n∑μ(kn)×F(n)=k∣n∑μ(kn)×(⌊nb⌋−⌊na−1⌋)×(⌊nd⌋−⌊nc−1⌋)
令 T T T为数据组数, w w w为 a , b , c , d a,b,c,d a,b,c,d的最大值,则每次询问的时间复杂度为 O ( w k ) O(\dfrac wk) O(kw),总时间复杂度为 O ( T × w k ) O(T\times \dfrac wk) O(T×kw),一些数据可能过不了,所以我们考虑优化。
对于式子中的 ( ⌊ b n ⌋ − ⌊ a − 1 n ⌋ ) × ( ⌊ d n ⌋ − ⌊ c − 1 n ⌋ ) (\lfloor \dfrac bn \rfloor-\lfloor \dfrac{a-1}{n} \rfloor)\times (\lfloor \dfrac dn \rfloor-\lfloor \dfrac{c-1}{n} \rfloor) (⌊nb⌋−⌊na−1⌋)×(⌊nd⌋−⌊nc−1⌋),我们可以用数论分块。对于一个左端点,取一个满足四个数都不变的右端点。总共能取 8 w 8\sqrt w 8w个值,于是每次询问的操作就优化到 O ( w ) O(\sqrt w) O(w),总时间复杂度为 O ( T w ) O(T\sqrt w) O(Tw)。
code
#include<bits/stdc++.h>
using namespace std;
const int N=200000;
int t,a,b,c,d,k,lst,z[N+5],p[N+5],mu[N+5],s[N+5];
long long ans;
int main()
{
mu[1]=1;
for(int i=2;i<=N;i++){
if(!z[i]){
p[++p[0]]=i;mu[i]=-1;
}
for(int j=1;j<=p[0]&&i*p[j]<=N;j++){
z[i*p[j]]=1;
if(i%p[j]==0){
mu[i*p[j]]=0;break;
}
mu[i*p[j]]=-mu[i];
}
}
for(int i=1;i<=N;i++){
s[i]=s[i-1]+mu[i];
}
scanf("%d",&t);
while(t--){
scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
ans=0;lst=0;
for(int i=k,vt;;i+=k){
vt=N;
if(a-1>=i) vt=min(vt,(a-1)/((a-1)/i));
if(b>=i) vt=min(vt,b/(b/i));
if(c-1>=i) vt=min(vt,(c-1)/((c-1)/i));
if(d>=i) vt=min(vt,d/(d/i));
if(vt>=N) break;
i=vt/k*k;
ans+=1ll*(s[i/k]-s[lst/k])*(b/i-(a-1)/i)*(d/i-(c-1)/i);
lst=i;
}
printf("%lld\n",ans);
}
return 0;
}