BZOJ传送门
Description
对于正整数
n
n
n,定义
f
(
n
)
f(n)
f(n)为
n
n
n所含质因子的最大幂指数。例如
f
(
1960
)
=
f
(
2
3
∗
5
1
∗
7
2
)
=
3
,
f
(
10007
)
=
1
,
f
(
1
)
=
0
f(1960)=f(2^3 * 5^1 * 7^2)=3, f(10007)=1, f(1)=0
f(1960)=f(23∗51∗72)=3,f(10007)=1,f(1)=0。
给定正整数
a
,
b
a,b
a,b,求
∑
∑
f
(
g
c
d
(
i
,
j
)
)
(
i
=
1..
a
,
j
=
1..
b
)
\sum\sum f(gcd(i,j)) (i=1..a, j=1..b)
∑∑f(gcd(i,j))(i=1..a,j=1..b)。
Input
第一行一个数
T
T
T,表示询问数。
接下来
T
T
T行,每行两个数
a
,
b
a,b
a,b,表示一个询问。
Output
对于每一个询问,输出一行一个非负整数作为回答。
Sample Input
4
7558588 9653114
6514903 4451211
7425644 1189442
6335198 4957
Sample Output
35793453939901
14225956593420
4332838845846
15400094813
HINT
【数据规模】
T ≤ 10000 T\le 10000 T≤10000
1 ≤ a , b ≤ 1 0 7 1\le a,b\le 10^7 1≤a,b≤107
解题分析
还是一波推式子:(不妨设
n
≤
m
n\le m
n≤m)
∑
i
=
1
n
∑
j
=
1
m
f
(
g
c
d
(
i
,
j
)
)
=
∑
d
=
1
n
f
(
d
)
∑
i
=
1
⌊
n
d
⌋
∑
j
=
1
⌊
m
d
⌋
[
g
c
d
(
i
,
j
)
=
1
]
=
∑
d
=
1
n
f
(
d
)
∑
e
=
1
⌊
n
d
⌋
μ
(
e
)
⌊
n
d
e
⌋
⌊
m
d
e
⌋
\sum_{i=1}^{n}\sum_{j=1}^mf(gcd(i,j)) \\ =\sum_{d=1}^{n}f(d)\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}[gcd(i,j)=1] \\ =\sum_{d=1}^{n}f(d)\sum_{e=1}^{\lfloor\frac{n}{d}\rfloor}\mu(e)\lfloor\frac{n}{de}\rfloor\lfloor\frac{m}{de}\rfloor
i=1∑nj=1∑mf(gcd(i,j))=d=1∑nf(d)i=1∑⌊dn⌋j=1∑⌊dm⌋[gcd(i,j)=1]=d=1∑nf(d)e=1∑⌊dn⌋μ(e)⌊den⌋⌊dem⌋
设
d
e
=
T
de=T
de=T, 那么:
∑
d
=
1
n
f
(
d
)
∑
e
=
1
⌊
n
d
⌋
μ
(
e
)
⌊
n
d
e
⌋
⌊
m
d
e
⌋
=
∑
T
=
1
n
⌊
n
T
⌋
⌊
m
T
⌋
∑
d
∣
T
μ
(
d
)
f
(
T
d
)
\sum_{d=1}^{n}f(d)\sum_{e=1}^{\lfloor\frac{n}{d}\rfloor}\mu(e)\lfloor\frac{n}{de}\rfloor\lfloor\frac{m}{de}\rfloor \\ =\sum_{T=1}^{n}\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor\sum_{d|T}\mu(d)f(\frac{T}{d})
d=1∑nf(d)e=1∑⌊dn⌋μ(e)⌊den⌋⌊dem⌋=T=1∑n⌊Tn⌋⌊Tm⌋d∣T∑μ(d)f(dT)
考虑如何计算
G
(
T
)
=
∑
d
∣
T
μ
(
d
)
f
(
T
d
)
G(T)=\sum_{d|T}\mu(d)f(\frac{T}{d})
G(T)=∑d∣Tμ(d)f(dT)。 显然我们要让
μ
(
d
)
≠
0
\mu(d)\ne 0
μ(d)̸=0, 从
T
T
T内取得的相同质因数就不应该超过一个。
考虑 T = p 1 a × . . . × p n a × p n + 1 b 1 × . . . × p n + m b m T=p_1^a\times ...\times p_n^a\times p_{n+1}^{b_1}\times ...\times p_{n+m}^{b_m} T=p1a×...×pna×pn+1b1×...×pn+mbm, 其中 a > b i a>b_i a>bi。
那么我们有两种选择:
- 将前 n n n个最高次幂的选到 d d d中, 后面随意选择, 这样得到的贡献是 ( f ( T ) − 1 ) × ( − 1 ) n × ∑ i = 0 m ( m i ) ( − 1 ) i (f(T)-1)\times(-1)^n\times\sum_{i=0}^{m}\binom{m}{i}(-1)^i (f(T)−1)×(−1)n×∑i=0m(im)(−1)i, 注意到后面当 m ≠ 0 m\ne 0 m̸=0的时候, 值为0, 当 m = 0 m=0 m=0的时候, 值为 ( f ( T ) − 1 ) × ( − 1 ) n (f(T)-1)\times (-1)^n (f(T)−1)×(−1)n。
- 不选完前 n n n个, 后面随意选择, 这样得到的贡献是 f ( T ) × ∑ i = 0 n − 1 ( n i ) × ( − 1 ) n × ∑ j = 0 m ( m j ) ( − 1 ) j f(T)\times \sum_{i=0}^{n-1}\binom{n}{i}\times (-1)^n\times \sum_{j=0}^{m}\binom{m}{j}(-1)^j f(T)×∑i=0n−1(in)×(−1)n×∑j=0m(jm)(−1)j, 同理当 m ≠ 0 m\ne 0 m̸=0的时候值为 0 0 0, 当 m = 0 m=0 m=0的时候, 值为 f ( T ) × ( − 1 ) ( n + 1 ) f(T)\times (-1)^{(n+1)} f(T)×(−1)(n+1)。
综上, G ( T ) G(T) G(T)当且仅当 T T T的质因数的指数齐次的时候有值, 值为 ( − 1 ) n + 1 (-1)^{n+1} (−1)n+1。
所以我们可以暴力筛出所有质数, 然后 D F S DFS DFS或筛出得到一次齐次的所有数, 然后向上累乘即可。 总复杂度 O ( N + T N ) O(N+T\sqrt N) O(N+TN)。
代码如下:
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#include <cstring>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 10000005
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 tim[MX], num[MX], pri[MX], sum[MX], buc[MX];
bool npr[MX], vis[MX];
int pcnt, tot;
void get_pri()
{
R int i, j, tar;
for (i = 2; i <= 1e7; ++i)
{
if (!npr[i]) pri[++pcnt] = i, num[i] = 1;
for (j = 1; j <= pcnt; ++j)
{
tar = pri[j] * i;
if (tar > 1e7) break;
npr[tar] = true;
if (!(i % pri[j])) break;
}
}
}
void DFS(R int pos, R int now, R int dep)
{
buc[++tot] = now, num[now] = dep;
long long tar;
for (R int i = pos + 1; i <= pcnt; ++i)
{
tar = 1ll * now * pri[i];
if (tar > 1e7) break;
DFS(i, tar, dep + 1);
}
}
int main(void)
{
get_pri();
DFS(0, 1, 0); long long mul;
for (R int i = 2; i <= tot; ++i)
{
for (mul = 1ll * buc[i] * buc[i]; mul <= 1e7; mul = mul * buc[i])
num[mul] = num[buc[i]];
}
for (R int i = 1; i <= 1e7; ++i)
{
if (!num[i]) sum[i] = sum[i - 1];
else sum[i] = sum[i - 1] + ((num[i] & 1) ? 1 : -1);
}
int T, n, m, lef, rig; in(T); long long ans;
W (T--)
{
in(n), in(m); ans = 0;
if (n > m) std::swap(n, m);
for (lef = 1; lef <= n; lef = rig + 1)
{
rig = std::min(n / (n / lef), m / (m / lef));
ans += 1ll * (n / lef) * (m / lef) * (sum[rig] - sum[lef - 1]);
}
printf("%lld\n", ans);
}
}