题目大意:
对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数。
1
≤
n
≤
50000
,
1
≤
a
≤
b
≤
50000
1≤n≤50000,1≤a≤b≤50000
1≤n≤50000,1≤a≤b≤50000
1
≤
c
≤
d
≤
50000
,
1
≤
k
≤
50000
1≤c≤d≤50000,1≤k≤50000
1≤c≤d≤50000,1≤k≤50000
分析:
设
d
x
,
y
d_{x,y}
dx,y表示
∑
i
=
1
x
∑
j
=
1
y
[
g
c
d
(
i
,
j
)
=
k
]
\sum_{i=1}^{x}\sum_{j=1}^{y}[gcd(i,j)=k]
∑i=1x∑j=1y[gcd(i,j)=k]
那答案容斥一下可以知道就是
d
b
,
d
−
d
a
−
1
,
d
−
d
b
,
c
−
1
+
d
a
−
1
,
c
−
1
d_{b,d}-d_{a-1,d}-d_{b,c-1}+d_{a-1,c-1}
db,d−da−1,d−db,c−1+da−1,c−1
那么我们考虑求
d
x
,
y
d_{x,y}
dx,y
d
x
,
y
d_{x,y}
dx,y
=
∑
i
=
1
x
∑
j
=
1
y
g
c
d
(
i
,
j
)
=
k
\sum_{i=1}^{x}\sum_{j=1}^{y}gcd(i,j)=k
∑i=1x∑j=1ygcd(i,j)=k
=
∑
i
=
1
⌊
x
k
⌋
∑
j
=
1
⌊
y
k
⌋
[
g
c
d
(
i
,
j
)
=
1
]
=\sum_{i=1}^{\left \lfloor \frac{x}{k} \right \rfloor}\sum_{j=1}^{\left \lfloor \frac{y}{k} \right \rfloor}[gcd(i,j)=1]
=∑i=1⌊kx⌋∑j=1⌊ky⌋[gcd(i,j)=1]
我们知道莫比乌斯函数有一个性质,
∑
d
∣
n
μ
(
d
)
=
[
n
=
1
]
\sum_{d|n}μ(d)=[n=1]
∑d∣nμ(d)=[n=1],
那么当
g
c
d
(
i
,
j
)
=
1
gcd(i,j)=1
gcd(i,j)=1时,
显然
∑
d
∣
g
c
d
(
i
,
j
)
μ
(
d
)
=
1
\sum_{d|gcd(i,j)}μ(d)=1
∑d∣gcd(i,j)μ(d)=1
那么
∑
i
=
1
⌊
x
k
⌋
∑
j
=
1
⌊
y
k
⌋
[
g
c
d
(
i
,
j
)
=
1
]
\sum_{i=1}^{\left \lfloor \frac{x}{k} \right \rfloor}\sum_{j=1}^{\left \lfloor \frac{y}{k} \right \rfloor}[gcd(i,j)=1]
∑i=1⌊kx⌋∑j=1⌊ky⌋[gcd(i,j)=1]
就可以写成
=
∑
i
=
1
⌊
x
k
⌋
∑
j
=
1
⌊
y
k
⌋
∑
d
∣
g
c
d
(
i
,
j
)
μ
(
d
)
=\sum_{i=1}^{\left \lfloor \frac{x}{k} \right \rfloor}\sum_{j=1}^{\left \lfloor \frac{y}{k} \right \rfloor} \sum_{d|gcd(i,j)}μ(d)
=∑i=1⌊kx⌋∑j=1⌊ky⌋∑d∣gcd(i,j)μ(d)
然后这个东西可以转换一下,安利一个博客,
https://www.cnblogs.com/NaVi-Awson/p/8318709.html
然后我们对于所有的
⌊
n
k
d
⌋
\left \lfloor \frac{n}{kd} \right \rfloor
⌊kdn⌋,可以发现取值最多只有
n
\sqrt{n}
n种,并且相同的都是连续的一段,那么我们就可以愉快的预处理出
m
o
b
i
u
s
mobius
mobius函数的前缀和,然后分块处理
⌊
n
k
d
⌋
\left \lfloor \frac{n}{kd} \right \rfloor
⌊kdn⌋,就可以求出
=
∑
i
=
1
⌊
x
k
⌋
∑
j
=
1
⌊
y
k
⌋
∑
d
∣
g
c
d
(
i
,
j
)
μ
(
d
)
=\sum_{i=1}^{\left \lfloor \frac{x}{k} \right \rfloor}\sum_{j=1}^{\left \lfloor \frac{y}{k} \right \rfloor} \sum_{d|gcd(i,j)}μ(d)
=∑i=1⌊kx⌋∑j=1⌊ky⌋∑d∣gcd(i,j)μ(d),就可以让每次查询的复杂度都达到根号级别。
代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#define N 50005
using namespace std;
typedef long long ll;
int prime[N], check[N], sum[N], mu[N], T, a, b, c, d, k, cnt;
void Get_mobius()
{
mu[1] = 1;
for (int i = 2; i <= 50000; i++)
{
if (!check[i])
{
prime[++cnt] = i;
mu[i] = -1;
}
for (int j = 1; j <= cnt; j++)
{
if (prime[j] * i > 50000) break;
check[prime[j] * i] = 1;
if (i % prime[j] == 0) { mu[prime[j] * i] = 0; break; }
else mu[prime[j] * i] = - mu[i];
}
}
for (int i = 1; i <= 50000; i++) sum[i] = sum[i - 1] + mu[i];
}
ll Cal(int x, int y)
{
ll num = 0;
if (x > y) swap(x, y);
for (int i = 1, last; i <= x; i = last + 1)
{
last = min(x / (x / i), y / (y / i));
num += (ll)(sum[last] - sum[i - 1]) * (x / i) * (y / i);
}
return num;
}
int main()
{
Get_mobius();
scanf("%d", &T);
while (T--)
{
scanf("%d %d %d %d %d", &a, &b, &c, &d, &k);
ll ans = Cal(b / k, d / k) - Cal((a - 1) / k, d / k) - Cal(b / k, (c - 1) / k) + Cal((a - 1) / k, (c - 1) / k);
printf("%lld\n", ans);
}
return 0;
}