洛谷传送门
BZOJ传送门
题目描述
对于给出的 n n n个询问,每次求有多少个数对 ( x , y ) (x,y) (x,y),满足 a ≤ x ≤ b a≤x≤b a≤x≤b, c ≤ y ≤ d c≤y≤d c≤y≤d,且 g c d ( x , y ) = k gcd(x,y) = k gcd(x,y)=k, g c d ( x , y ) gcd(x,y) gcd(x,y)函数为 x x x和 y y y的最大公约数。
输入输出格式
输入格式:
第一行一个整数 n n n,接下来 n n n行每行五个整数,分别表示 a a a、 b b b、 c c c、 d d d、 k k k
输出格式:
共 n n n行,每行一个整数表示满足要求的数对 ( x , y ) (x,y) (x,y)的个数
输入输出样例
输入样例#1:
2
2 5 1 5 1
1 5 1 5 2
输出样例#1:
14
3
说明
100%的数据满足: 1 ≤ n ≤ 50000 , 1 ≤ a ≤ b ≤ 50000 , 1 ≤ c ≤ d ≤ 50000 , 1 ≤ k ≤ 50000 1≤n≤50000,1≤a≤b≤50000,1≤c≤d≤50000,1≤k≤50000 1≤n≤50000,1≤a≤b≤50000,1≤c≤d≤50000,1≤k≤50000
解题分析
我们先推出这个玩意怎么求, 其他的可以通过作差得到(不妨设
n
≤
m
n\le m
n≤m):
∑
i
=
1
n
∑
j
=
1
m
[
g
c
d
(
i
,
j
)
=
k
]
=
∑
i
=
1
⌊
n
k
⌋
∑
j
=
1
⌊
m
k
⌋
[
g
c
d
(
i
,
j
)
=
1
]
=
∑
i
=
1
⌊
n
k
⌋
∑
j
=
1
⌊
m
k
⌋
∑
d
∣
g
c
d
(
i
,
j
)
μ
(
d
)
=
∑
d
=
1
⌊
n
k
⌋
μ
(
d
)
⌊
⌊
n
k
⌋
d
⌋
⌊
⌊
m
k
⌋
d
⌋
\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_{i=1}^{\lfloor\frac{n}{k}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{k}\rfloor}\sum_{d|gcd(i,j)}\mu(d) \\ =\sum_{d=1}^{\lfloor\frac{n}{k}\rfloor}\mu(d)\lfloor\frac{\lfloor\frac{n}{k}\rfloor}{d}\rfloor\lfloor\frac{\lfloor\frac{m}{k}\rfloor}{d}\rfloor
i=1∑nj=1∑m[gcd(i,j)=k]=i=1∑⌊kn⌋j=1∑⌊km⌋[gcd(i,j)=1]=i=1∑⌊kn⌋j=1∑⌊km⌋d∣gcd(i,j)∑μ(d)=d=1∑⌊kn⌋μ(d)⌊d⌊kn⌋⌋⌊d⌊km⌋⌋
然后线筛
μ
(
i
)
\mu(i)
μ(i), 下底分块即可。
代码如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define ll long long
#define MX 50050
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
int pcnt;
int miu[MX], pri[MX];
bool npr[MX];
void get_miu()
{
R int i, j, tar;
miu[1] = 1;
for (i = 2; i <= 50000; ++i)
{
if (!npr[i]) pri[++pcnt] = i, miu[i] = -1;
for (j = 1; j <= pcnt; ++j)
{
tar = i * pri[j];
if (tar > 50000) break;
npr[tar] = true;
if (!(i % pri[j])) {miu[tar] = 0; break;}
miu[tar] = -miu[i];
}
}
for (R int i = 1; i <= 50000; ++i) miu[i] += miu[i - 1];
}
IN ll calc(R int up1, R int up2, R int k)
{
if (up1 > up2) std::swap(up1, up2);
int bd = up1 / k, bd2 = up2 / k;
R int lef = 1, rig;
ll ret = 0;
W (lef <= bd)
{
rig = std::min(bd / (bd / lef), bd2 / (bd2 / lef));
ret += 1ll *(miu[rig] - miu[lef - 1]) * (bd / lef) * (bd2 / lef);
lef = rig + 1;
}
return ret;
}
int main()
{
int T, a, b, c, d, k;
in(T); get_miu();
W (T--)
{
in(a), in(b), in(c), in(d), in(k);
ll ans = calc(b, d, k) - calc(a - 1, d, k) - calc(b, c - 1, k) + calc(a - 1, c - 1, k);
printf("%lld\n", ans);
}
}