思路基本同 P4240 毒瘤之神的考验。
Description
-
多测, T T T 组数据。
-
给定整数 n , m n, m n,m,请求出
[ ∑ i = 1 n ∑ j = 1 m φ ( lcm ( i , j ) gcd ( i , j ) ) ] m o d 23333 \left[\sum_{i = 1}^n \sum_{j = 1}^m \varphi\left(\dfrac{\operatorname{lcm}(i, j)}{\gcd(i, j)} \right) \right] \bmod 23333 [i=1∑nj=1∑mφ(gcd(i,j)lcm(i,j))]mod23333 -
T ≤ 3 × 1 0 4 , m ≤ n ≤ 5 × 1 0 4 T\le 3\times 10^4, m\le n\le 5\times 10^4 T≤3×104,m≤n≤5×104。
Solution
不妨设
n
≤
m
n\le m
n≤m。
a
n
s
=
∑
d
=
1
n
∑
i
=
1
n
∑
j
=
1
m
φ
(
i
j
d
2
)
[
gcd
(
i
,
j
)
=
d
]
=
∑
d
=
1
n
∑
i
=
1
⌊
n
d
⌋
∑
j
=
1
⌊
m
d
⌋
φ
(
i
j
)
[
gcd
(
i
,
j
)
=
1
]
=
∑
d
=
1
n
∑
i
=
1
⌊
n
d
⌋
φ
(
i
)
∑
j
=
1
⌊
m
d
⌋
φ
(
j
)
[
gcd
(
i
,
j
)
=
1
]
=
∑
d
=
1
n
∑
k
=
1
⌊
n
d
⌋
μ
(
k
)
∑
i
=
1
⌊
n
d
k
⌋
φ
(
i
k
)
∑
j
=
1
⌊
m
d
k
⌋
φ
(
j
k
)
=
∑
T
=
1
n
∑
k
∣
T
μ
(
k
)
∑
i
=
1
⌊
n
T
⌋
φ
(
i
k
)
∑
j
=
1
⌊
m
T
⌋
φ
(
j
k
)
\begin{aligned} ans & = \sum_{d = 1}^n \sum_{i = 1}^n \sum_{j = 1}^m \varphi\left(\dfrac{ij}{d^2} \right) [\gcd(i, j) = d] \\ & = \sum_{d = 1}^n \sum_{i = 1}^{\left\lfloor\frac{n}{d}\right\rfloor} \sum_{j = 1}^{\left\lfloor\frac{m}{d}\right\rfloor} \varphi(ij) [\gcd(i, j) = 1] \\ & = \sum_{d = 1}^n \sum_{i = 1}^{\left\lfloor\frac{n}{d}\right\rfloor} \varphi(i) \sum_{j = 1}^{\left\lfloor\frac{m}{d}\right\rfloor} \varphi(j) [\gcd(i, j) = 1] \\ & = \sum_{d = 1}^n \sum_{k = 1}^{\left\lfloor\frac{n}{d}\right\rfloor} \mu(k) \sum_{i = 1}^{\left\lfloor\frac{n}{dk}\right\rfloor} \varphi(ik) \sum_{j = 1}^{\left\lfloor\frac{m}{dk}\right\rfloor} \varphi(jk) \\ & = \sum_{T = 1}^n \sum_{k\mid T} \mu(k) \sum_{i = 1}^{\left\lfloor\frac{n}{T}\right\rfloor} \varphi(ik) \sum_{j = 1}^{\left\lfloor\frac{m}{T}\right\rfloor} \varphi(jk) \end{aligned}
ans=d=1∑ni=1∑nj=1∑mφ(d2ij)[gcd(i,j)=d]=d=1∑ni=1∑⌊dn⌋j=1∑⌊dm⌋φ(ij)[gcd(i,j)=1]=d=1∑ni=1∑⌊dn⌋φ(i)j=1∑⌊dm⌋φ(j)[gcd(i,j)=1]=d=1∑nk=1∑⌊dn⌋μ(k)i=1∑⌊dkn⌋φ(ik)j=1∑⌊dkm⌋φ(jk)=T=1∑nk∣T∑μ(k)i=1∑⌊Tn⌋φ(ik)j=1∑⌊Tm⌋φ(jk)
套路地设出来
f
(
k
,
n
)
=
∑
i
=
1
n
φ
(
i
k
)
f(k, n) = \sum_{i = 1}^n \varphi(ik)
f(k,n)=i=1∑nφ(ik)
那么
a
n
s
=
∑
T
=
1
n
∑
k
∣
T
μ
(
k
)
f
(
k
,
⌊
n
T
⌋
)
f
(
k
,
⌊
m
T
⌋
)
ans = \sum_{T = 1}^n \sum_{k\mid T} \mu(k) f\left(k, \left\lfloor\dfrac{n}{T}\right\rfloor \right) f\left(k, \left\lfloor\dfrac{m}{T}\right\rfloor \right)
ans=T=1∑nk∣T∑μ(k)f(k,⌊Tn⌋)f(k,⌊Tm⌋)
又有递推式
f
(
k
,
n
)
=
f
(
k
,
n
−
1
)
+
φ
(
n
k
)
f(k, n) = f(k, n - 1) + \varphi(nk)
f(k,n)=f(k,n−1)+φ(nk)
即
f
f
f 可以在
Θ
(
n
ln
n
)
\Theta(n\ln n)
Θ(nlnn) 时间内预处理。
但是这个 f f f 带一个 k k k,无法整除分块,只能暴力,所以查询是 O ( T ∑ i = 1 n n i ) ≃ O ( T n ln n ) \Omicron(T\sum\limits_{i = 1}^n \dfrac{n}{i}) \simeq \Omicron(T n\ln n) O(Ti=1∑nin)≃O(Tnlnn) 的。
我们想要整除分块,那就弄个前缀和。
把整个表示出来
g
(
n
,
m
,
l
)
=
∑
i
=
1
l
∑
k
∣
i
μ
(
k
)
f
(
k
,
n
)
f
(
k
,
m
)
g(n, m, l) = \sum_{i = 1}^l \sum_{k\mid i} \mu(k) f(k, n) f(k, m)
g(n,m,l)=i=1∑lk∣i∑μ(k)f(k,n)f(k,m)
那么整除分块大概长这样
g
(
⌊
n
l
⌋
,
⌊
m
l
⌋
,
r
)
−
g
(
⌊
n
l
⌋
,
⌊
m
l
⌋
,
l
−
1
)
g\left(\left\lfloor\dfrac{n}{l}\right\rfloor, \left\lfloor\dfrac{m}{l}\right\rfloor, r \right) - g\left(\left\lfloor\dfrac{n}{l}\right\rfloor, \left\lfloor\dfrac{m}{l}\right\rfloor, l - 1 \right)
g(⌊ln⌋,⌊lm⌋,r)−g(⌊ln⌋,⌊lm⌋,l−1)
同样有递推式
g
(
n
,
m
,
l
)
=
g
(
n
,
m
,
l
−
1
)
+
∑
k
∣
l
μ
(
k
)
f
(
k
,
n
)
f
(
k
,
m
)
g(n, m, l) = g(n, m, l - 1) + \sum_{k\mid l} \mu(k) f(k, n) f(k, m)
g(n,m,l)=g(n,m,l−1)+k∣l∑μ(k)f(k,n)f(k,m)
预处理是
O
(
n
∑
i
=
1
n
(
∑
j
=
1
n
i
n
j
)
+
n
i
)
≃
O
(
n
3
)
\Omicron\left(n \sum_{i = 1}^n \left(\sum_{j = 1}^{\frac{n}{i}} \dfrac{n}{j}\right) + \dfrac{n}{i} \right) \simeq \Omicron(n^3)
O⎝⎛ni=1∑n⎝⎛j=1∑injn⎠⎞+in⎠⎞≃O(n3)
会
T
L
E
+
M
L
E
\rm TLE + MLE
TLE+MLE。
但是它能够做到十分优秀的 O ( T n ) \Omicron(T \sqrt{n}) O(Tn) 回答。
如果要将两种方法结合,那么就是大家喜闻乐见的 根号分治 了。
(其实题目背景已经有提示了)
A:“数论,分块。”
设 k k k 为阈值,表示预处理 g ( n , m , l ) g(n, m, l) g(n,m,l) 时 n , m n, m n,m 只处理到 k k k。
那么计算时对于 l ≤ ⌊ n k ⌋ l \le \left\lfloor\dfrac{n}{k}\right\rfloor l≤⌊kn⌋ 的直接暴力;对于 l > ⌊ n k ⌋ l > \left\lfloor\dfrac{n}{k}\right\rfloor l>⌊kn⌋ 的部分,有 ⌊ n l ⌋ ≤ k \left\lfloor\dfrac{n}{l}\right\rfloor \le k ⌊ln⌋≤k,直接用预处理过的 g g g。
Code
//18 = 9 + 9 = 18.
#include <iostream>
#include <cstdio>
#include <vector>
#define Debug(x) cout << #x << "=" << x << endl
typedef long long ll;
using namespace std;
const int MAXN = 5e4 + 5;
const int N = 5e4;
const int MAXK = 155;
const int K = 150;
const int MOD = 23333;
typedef int arr[MAXN];
int add(int a, int b) {return (a + b) % MOD;}
int sub(int a, int b) {return (a - b + MOD) % MOD;}
int mul(int a, int b) {return (ll)a * b % MOD;}
arr p, mu, phi;
bool vis[MAXN];
vector<int> f[MAXN], g[MAXK][MAXK];
void pre()
{
mu[1] = phi[1] = 1;
for (int i = 2; i <= N; i++)
{
if (!vis[i])
{
p[++p[0]] = i;
mu[i] = MOD - 1;
phi[i] = (i - 1) % MOD;
}
for (int j = 1; j <= p[0] && i * p[j] <= N; j++)
{
vis[i * p[j]] = true;
if (i % p[j] == 0)
{
mu[i * p[j]] = 0;
phi[i * p[j]] = mul(phi[i], p[j]);
break;
}
mu[i * p[j]] = mul(mu[i], mu[p[j]]);
phi[i * p[j]] = mul(phi[i], phi[p[j]]);
}
}
for (int k = 1; k <= N; k++)
{
f[k].resize(N / k + 5);
for (int n = 1; n <= N / k; n++)
{
f[k][n] = add(f[k][n - 1], phi[n * k]);
}
}
for (int n = 1; n <= K; n++)
{
for (int m = n; m <= K; m++)
{
g[n][m].resize(N / m + 5);
for (int i = 1; i <= N / m; i++)
{
int wjy = mul(mu[i], mul(f[i][n], f[i][m]));
for (int j = 1; j <= N / m / i; j++)
{
g[n][m][i * j] = add(g[n][m][i * j], wjy);
}
}
for (int l = 1; l <= N / m; l++)
{
g[n][m][l] = add(g[n][m][l], g[n][m][l - 1]);
}
}
}
}
int block(int n, int m)
{
if (n > m)
{
swap(n, m);
}
int res = 0, xsy = m / K;
for (int i = 1; i <= xsy; i++)
{
for (int j = 1; j <= xsy / i; j++)
{
int t = i * j;
res = add(res, mul(mu[i], mul(f[i][n / t], f[i][m / t])));
}
}
for (int l = xsy + 1, r; l <= n; l = r + 1)
{
int k1 = n / l, k2 = m / l;
r = min(n / k1, m / k2);
res = add(res, sub(g[k1][k2][r], g[k1][k2][l - 1]));
}
return res;
}
int main()
{
pre();
int t;
scanf("%d", &t);
while (t--)
{
int n, m;
scanf("%d%d", &n, &m);
printf("%d\n", block(n, m));
}
return 0;
}