洛谷传送门
BZOJ传送门
题目描述
神犇YY虐完数论后给傻×kAc出了一题
给定 N , M N, M N,M,求 1 ≤ x ≤ N , 1 ≤ y ≤ M 1\le x\le N, 1\le y\le M 1≤x≤N,1≤y≤M且 g c d ( x , y ) gcd(x, y) gcd(x,y)为质数的 ( x , y ) (x, y) (x,y)有多少对
kAc这种傻×必然不会了,于是向你来请教……
多组输入
输入输出格式
输入格式:
第一行一个整数 T T T 表述数据组数
接下来 T T T行,每行两个正整数,表示 N , M N, M N,M
输出格式:
T T T行,每行一个整数表示第i组数据的结果
输入输出样例
输入样例#1:
2
10 10
100 100
输出样例#1:
30
2791
说明
T = 10000 T = 10000 T=10000
N , M ≤ 10000000 N, M \le 10000000 N,M≤10000000
解题分析
先简化式子:(仍然不妨设
n
≤
m
n \le m
n≤m)
∑
i
=
1
n
∑
j
=
1
m
[
g
c
d
(
i
,
j
)
∈
p
r
i
m
e
]
=
∑
p
≤
n
,
p
∈
p
r
i
m
e
∑
i
=
1
n
∑
j
=
1
m
[
g
c
d
(
i
,
j
)
=
p
]
=
∑
p
≤
n
,
p
∈
p
r
i
m
e
∑
i
=
1
⌊
n
p
⌋
∑
j
=
1
⌊
m
p
⌋
∑
d
∣
g
c
d
(
i
,
j
)
μ
(
d
)
=
∑
p
≤
n
,
p
∈
p
r
i
m
e
∑
d
=
1
⌊
n
p
⌋
μ
(
d
)
⌊
n
d
p
⌋
⌊
m
d
p
⌋
\sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)\in prime] \\ =\sum_{p\le n,p\in prime}\sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)=p] \\ =\sum_{p\le n,p\in prime}\sum_{i=1}^{\lfloor\frac{n}{p}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{p}\rfloor}\sum_{d|gcd(i,j)}\mu(d) \\ =\sum_{p\le n,p\in prime}\sum_{d=1}^{\lfloor\frac{n}{p}\rfloor}\mu(d)\lfloor\frac{n}{dp}\rfloor\lfloor\frac{m}{dp}\rfloor
i=1∑nj=1∑m[gcd(i,j)∈prime]=p≤n,p∈prime∑i=1∑nj=1∑m[gcd(i,j)=p]=p≤n,p∈prime∑i=1∑⌊pn⌋j=1∑⌊pm⌋d∣gcd(i,j)∑μ(d)=p≤n,p∈prime∑d=1∑⌊pn⌋μ(d)⌊dpn⌋⌊dpm⌋
设
T
=
d
p
T=dp
T=dp
∑
p
≤
n
,
p
∈
p
r
i
m
e
∑
d
=
1
⌊
n
p
⌋
μ
(
d
)
⌊
n
d
p
⌋
⌊
m
d
p
⌋
=
∑
T
=
1
n
⌊
n
T
⌋
⌊
m
T
⌋
∑
d
∣
T
μ
(
d
)
[
T
d
∈
p
r
i
m
e
]
\sum_{p\le n,p\in prime}\sum_{d=1}^{\lfloor\frac{n}{p}\rfloor}\mu(d)\lfloor\frac{n}{dp}\rfloor\lfloor\frac{m}{dp}\rfloor \\= \sum_{T=1}^{n}\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor\sum_{d|T}\mu(d)[\frac{T}{d}\in prime]
p≤n,p∈prime∑d=1∑⌊pn⌋μ(d)⌊dpn⌋⌊dpm⌋=T=1∑n⌊Tn⌋⌊Tm⌋d∣T∑μ(d)[dT∈prime]
设
G
(
x
)
=
∑
d
∣
x
μ
(
d
)
[
x
d
∈
p
r
i
m
e
]
G(x)=\sum_{d|x}\mu(d)[\frac{x}{d}\in prime]
G(x)=∑d∣xμ(d)[dx∈prime],
x
=
p
×
q
,
p
∈
p
r
i
m
e
x=p\times q, p\in prime
x=p×q,p∈prime, 考虑如何筛这个玩意。
- x x x为质数, G ( x ) = 1 G(x)=1 G(x)=1。
- 新加入的一个质数 p p p在原来的 q q q中间出现过了, 即 q m o d p = 0 q\ mod\ p=0 q mod p=0, 那么只有当 x d = p \frac{x}{d}=p dx=p的时候可能有值, 所以 G ( x ) = μ ( q ) G(x)=\mu (q) G(x)=μ(q)。
- 新加入的一个质数 p p p在原来的 q q q中间没有出现, 那么当 p ∣ d p|d p∣d的时候, 得到的值为 − G ( q ) -G(q) −G(q), 当 x d = p \frac{x}{d}=p dx=p的时候, 得到的值为 μ ( q ) \mu(q) μ(q), 所以 G ( x ) = − G ( q ) + μ ( q ) G(x)=-G(q)+\mu(q) G(x)=−G(q)+μ(q)。
这样我们就可以线筛 G ( x ) G(x) G(x)了, 结合下底分块即可 A C AC AC。
代码如下:
#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 MX 10000050
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;
}
template <class T> IN T min(T a, T b) {return a < b ? a : b;}
int pcnt;
int pri[MX], F[MX], sum[MX], miu[MX];
bool npr[MX];
IN void get()
{
F[1] = 0, miu[1] = 1;
R int i, j, tar;
for (i = 2; i <= 1e7; ++i)
{
if (!npr[i]) pri[++pcnt] = i, miu[i] = -1, F[i] = 1;
for (j = 1; j <= pcnt; ++j)
{
tar = i * pri[j];
if (tar > 1e7) break;
npr[tar] = true;
if (!(i % pri[j]))
{
F[tar] = miu[i];
miu[tar] = 0;
break;
}
miu[tar] = -miu[i];
F[tar] = miu[i] - F[i];
}
}
for (R int i = 1; i <= 1e7; ++i) sum[i] = sum[i - 1] + F[i];
}
int main(void)
{
int T, n, m;
R int lef, rig;
long long ans;
in(T); get();
W (T--)
{
in(n), in(m); ans = 0;
if (n > m) std::swap(n, m);
lef = 1;
for (; lef <= n; lef = rig + 1)
{
rig = min(n / (n / lef), m / (m / lef));
ans += 1ll * (sum[rig] - sum[lef - 1]) * (n / lef) * (m / lef);
}
printf("%lld\n", ans);
}
}