题目
题目概要
求
∑
i
∈
[
a
,
b
]
,
j
∈
[
c
,
d
]
gcd
(
i
,
j
)
=
k
1
\sum_{i\in[a,b],j\in[c,d]}^{\gcd(i,j)=k}1
i∈[a,b],j∈[c,d]∑gcd(i,j)=k1
数据范围与约定
数据组数
T
≤
50000
T\le 50000
T≤50000 ,
a
,
b
,
c
,
d
,
k
≤
5
×
1
0
4
a,b,c,d,k\le 5\times 10^4
a,b,c,d,k≤5×104 ,
a
≤
b
a\le b
a≤b 且
c
≤
d
c\le d
c≤d 。
思路
既然 k k k 是已知的,直接枚举 i k \frac ik ki 和 j k \frac jk kj 好了。不妨设 k ∣ a , k ∣ b , k ∣ c , k ∣ d k|a,k|b,k|c,k|d k∣a,k∣b,k∣c,k∣d 。
∑ i = a / k b / k ∑ j = c / k d / k [ gcd ( i , j ) = 1 ] \sum_{i=a/k}^{b/k}\sum_{j=c/k}^{d/k}[\gcd(i,j)=1] i=a/k∑b/kj=c/k∑d/k[gcd(i,j)=1]
考虑容斥计算。去掉有公因子 2 , 3 , 5 , 7 , … 2,3,5,7,\dots 2,3,5,7,… 的,加上 2 × 3 , 2 × 5 , 3 × 5 , … 2\times 3,2\times 5,3\times 5,\dots 2×3,2×5,3×5,… 的,而后再减去……
这个可以套个莫比乌斯函数来快速求符号。然后整除分块加速。每组数据复杂度 O ( n ) \mathcal O(\sqrt n) O(n) 。
代码
#include <cstdio>
#include <iostream>
#include <vector>
using namespace std;
typedef long long int_;
// #define int_ long long
int readint(){
int a = 0; char c = getchar(), f = 1;
for(; c<'0'||c>'9'; c=getchar())
if(c == '-') f = -f;
for(; '0'<=c&&c<='9'; c=getchar())
a = (a<<3)+(a<<1)+(c^48);
return a*f;
}
template < typename T >
void getMin(T&a,const T&b){if(b<a)a=b;}
const int MaxN = 50005;
bool isPrime[MaxN];
vector< int > primes;
int mu[MaxN];
void sievePrime(int n){
mu[1] = 1;
for(int i=2; i<=n; ++i)
isPrime[i] = true;
for(int i=2,len=0; i<=n; ++i){
if(isPrime[i]){
primes.push_back(i);
mu[i] = -1, ++ len;
}
for(int j=0; j<len; ++j){
if(primes[j] > n/i) break;
isPrime[i*primes[j]] = 0;
if(i%primes[j] == 0){
mu[i*primes[j]] = 0;
break;
}
mu[i*primes[j]] = -mu[i];
}
}
}
int main(){
int a, b, c, d;
sievePrime(MaxN-5);
for(int i=2; i<=MaxN-5; ++i)
mu[i] += mu[i-1];
for(int T=readint(); T; --T){
a = readint(), b = readint();
c = readint(), d = readint();
int k = readint();
a = (a-1)/k, b /= k;
c = (c-1)/k, d /= k;
int_ ans = 0;
for(int l=1,r; l<=b&&l<=d; l=r+1){
r = min(b/(b/l),d/(d/l));
if(l <= a) getMin(r,a/(a/l));
if(l <= c) getMin(r,c/(c/l));
int cnt1 = (b/l)-(a/l);
int cnt2 = (d/l)-(c/l);
int_ cnt3 = mu[r]-mu[l-1];
ans += cnt3*cnt1*cnt2;
}
printf("%lld\n",ans);
}
return 0;
}