推式子
a
n
s
=
∑
i
=
1
N
∑
j
=
1
M
l
c
m
(
i
,
j
)
=
∑
i
=
1
N
∑
j
=
1
M
i
∗
j
gcd
(
i
,
j
)
\begin{aligned} ans = \sum_{i=1}^{N}\sum_{j=1}^{M}lcm(i,j) = \sum_{i=1}^{N}\sum_{j=1}^{M}\frac{i*j}{\gcd(i,j)} \end{aligned}
ans=i=1∑Nj=1∑Mlcm(i,j)=i=1∑Nj=1∑Mgcd(i,j)i∗j
很明显出现了
gcd
\gcd
gcd,我们枚举
gcd
(
i
,
j
)
=
d
\gcd(i,j)=d
gcd(i,j)=d
a
n
s
=
∑
d
=
1
min
(
N
,
M
)
∑
i
=
1
N
∑
j
=
1
M
i
∗
j
d
[
gcd
(
i
,
j
)
=
=
d
]
\begin{aligned} ans = \sum_{d=1}^{\min(N,M)}\sum_{i=1}^{N}\sum_{j=1}^{M}\frac{i*j}{d}[\gcd(i,j)==d] \end{aligned}
ans=d=1∑min(N,M)i=1∑Nj=1∑Mdi∗j[gcd(i,j)==d]
a
n
s
=
∑
d
=
1
min
(
N
,
M
)
∑
i
=
1
⌊
N
d
⌋
∑
j
=
1
⌊
M
d
⌋
d
∗
i
∗
j
[
gcd
(
i
,
j
)
=
=
1
]
\begin{aligned} ans = \sum_{d=1}^{\min(N,M)}\sum_{i=1}^{\lfloor\frac{N}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{M}{d}\rfloor}d*i*j[\gcd(i,j)==1] \end{aligned}
ans=d=1∑min(N,M)i=1∑⌊dN⌋j=1∑⌊dM⌋d∗i∗j[gcd(i,j)==1]
接下来我们有很多方法去化简这个式子,我使用
∑
x
∣
g
c
d
(
i
,
j
)
μ
(
x
)
\sum_{x \mid gcd(i,j)}\mu(x)
∑x∣gcd(i,j)μ(x)替换
[
gcd
(
i
,
j
)
=
=
1
]
[\gcd(i,j) == 1]
[gcd(i,j)==1]
a
n
s
=
∑
d
=
1
min
(
N
,
M
)
∑
i
=
1
⌊
N
d
⌋
∑
j
=
1
⌊
M
d
⌋
d
∗
i
∗
j
∑
x
∣
g
c
d
(
i
,
j
)
μ
(
x
)
\begin{aligned} ans = \sum_{d=1}^{\min(N,M)}\sum_{i=1}^{\lfloor\frac{N}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{M}{d}\rfloor}d*i*j\sum_{x \mid gcd(i,j)}\mu(x) \end{aligned}
ans=d=1∑min(N,M)i=1∑⌊dN⌋j=1∑⌊dM⌋d∗i∗jx∣gcd(i,j)∑μ(x)
然后我们枚举x
a
n
s
=
∑
d
=
1
min
(
N
,
M
)
d
∑
x
=
1
min
(
N
d
,
M
d
)
μ
(
x
)
∑
x
i
=
1
⌊
N
d
⌋
∑
x
j
=
1
⌊
M
d
⌋
x
2
∗
i
∗
j
\begin{aligned} ans = \sum_{d=1}^{\min(N,M)}d\sum_{x=1}^{\min(\frac{N}{d},\frac{M}{d})}\mu(x)\sum_{xi=1}^{\lfloor\frac{N}{d}\rfloor}\sum_{xj=1}^{\lfloor\frac{M}{d}\rfloor}x^{2}*i*j \end{aligned}
ans=d=1∑min(N,M)dx=1∑min(dN,dM)μ(x)xi=1∑⌊dN⌋xj=1∑⌊dM⌋x2∗i∗j
a
n
s
=
∑
d
=
1
min
(
N
,
M
)
d
∑
x
=
1
min
(
N
d
,
M
d
)
μ
(
x
)
∗
x
2
∑
i
=
1
⌊
N
x
d
⌋
∑
j
=
1
⌊
M
x
d
⌋
i
∗
j
\begin{aligned} ans = \sum_{d=1}^{\min(N,M)}d\sum_{x=1}^{\min(\frac{N}{d},\frac{M}{d})}\mu(x)*x^{2}\sum_{i=1}^{\lfloor\frac{N}{xd}\rfloor}\sum_{j=1}^{\lfloor\frac{M}{xd}\rfloor}i*j \end{aligned}
ans=d=1∑min(N,M)dx=1∑min(dN,dM)μ(x)∗x2i=1∑⌊xdN⌋j=1∑⌊xdM⌋i∗j
推到这里就可以写了,两次分块时间复杂度接近O(n)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
template <typename T>
void out(T x) { cout << x << endl; }
const int N = 1e7 + 6;
const ll mod = 20101009;
const ll inv2 = 10050505;
ll fast_pow(ll a, ll b, ll p) {ll c = 1; while(b) { if(b & 1) c = c * a % p; a = a * a % p; b >>= 1;} return c;}
int mu[N], prime[N], tot;
ll sum[N];
bool mark[N];
void get_mu()
{
tot = 0;
mark[0] = mark[1] = true;
mu[1] = 1;
for(int i = 2; i < N; i ++)
{
if(!mark[i])
{
prime[tot ++] = i;
mu[i] = -1;
}
for(int j = 0; j < tot && i * prime[j] < N; j ++)
{
mark[i * prime[j]] = true;
if(i % prime[j] == 0)
break;
mu[i * prime[j]] = -mu[i];
}
}
for(int i = 1; i < N; i ++)
sum[i] = (sum[i - 1] + mu[i] * i % mod * i % mod) % mod;
}
int main()
{
ios::sync_with_stdio(false);
get_mu();
ll n, m;
cin >> n >> m;
if(n > m)
swap(n, m);
ll ans = 0;
for(ll d = 1, t = 1; d <= n; d = t + 1)
{
t = min(n / (n / d), m / (m / d));
ll bns = 0, dn = n / d, dm = m / d;
for(ll i = 1, j = 1; i <= dn; i = j + 1)
{
j = min(dn / (dn / i), dm / (dm / i));
bns = (bns + (sum[j] - sum[i - 1]) * (dn / i) % mod * (dn / i + 1ll) % mod * inv2 % mod * (dm / i) % mod * (dm / i + 1ll) % mod * inv2 % mod + mod) % mod;
}
ans = (ans + (t - d + 1) * (t + d) % mod * inv2 % mod * bns % mod + mod) % mod;
}
cout << ans << endl;
}
然后就这样我们还可以继续化简
我们令
T
=
x
d
T=xd
T=xd,令
f
(
x
)
=
∑
i
=
1
x
i
f(x)=\sum_{i=1}^{x}i
f(x)=∑i=1xi
a
n
s
=
∑
d
=
1
min
(
N
,
M
)
d
∑
x
=
1
min
(
N
d
,
M
d
)
μ
(
x
)
∗
x
2
f
(
⌊
N
T
⌋
)
f
(
⌊
M
T
⌋
)
\begin{aligned} ans = \sum_{d=1}^{\min(N,M)}d\sum_{x=1}^{\min(\frac{N}{d},\frac{M}{d})}\mu(x)*x^{2}f(\lfloor\frac{N}{T}\rfloor)f(\lfloor\frac{M}{T}\rfloor) \end{aligned}
ans=d=1∑min(N,M)dx=1∑min(dN,dM)μ(x)∗x2f(⌊TN⌋)f(⌊TM⌋)
然后我们枚举T
a
n
s
=
∑
T
=
1
min
(
N
,
M
)
f
(
⌊
N
T
⌋
)
f
(
⌊
M
T
⌋
)
∑
d
∣
T
d
∗
μ
(
T
d
)
∗
(
T
d
)
2
\begin{aligned} ans = \sum_{T=1}^{\min(N,M)}f(\lfloor\frac{N}{T}\rfloor)f(\lfloor\frac{M}{T}\rfloor)\sum_{d \mid T}d*\mu(\frac{T}{d})*(\frac{T}{d})^{2} \end{aligned}
ans=T=1∑min(N,M)f(⌊TN⌋)f(⌊TM⌋)d∣T∑d∗μ(dT)∗(dT)2
a
n
s
=
∑
T
=
1
min
(
N
,
M
)
f
(
⌊
N
T
⌋
)
f
(
⌊
M
T
⌋
)
∑
d
∣
T
μ
(
T
d
)
∗
(
T
d
)
∗
T
\begin{aligned} ans = \sum_{T=1}^{\min(N,M)}f(\lfloor\frac{N}{T}\rfloor)f(\lfloor\frac{M}{T}\rfloor)\sum_{d \mid T}\mu(\frac{T}{d})*(\frac{T}{d})*T \end{aligned}
ans=T=1∑min(N,M)f(⌊TN⌋)f(⌊TM⌋)d∣T∑μ(dT)∗(dT)∗T
后面那个式子我们枚举
T
d
\frac{T}{d}
dT,即另
d
=
T
d
d=\frac{T}{d}
d=dT
a
n
s
=
∑
T
=
1
min
(
N
,
M
)
f
(
⌊
N
T
⌋
)
f
(
⌊
M
T
⌋
)
∑
d
∣
T
d
∗
μ
(
d
)
∗
T
\begin{aligned} ans = \sum_{T=1}^{\min(N,M)}f(\lfloor\frac{N}{T}\rfloor)f(\lfloor\frac{M}{T}\rfloor)\sum_{d \mid T}d*\mu(d)*T \end{aligned}
ans=T=1∑min(N,M)f(⌊TN⌋)f(⌊TM⌋)d∣T∑d∗μ(d)∗T
这样似乎并没有改变什么复杂度,但是我们发现后面的
∑
d
∣
T
d
∗
μ
(
d
)
是
个
积
性
函
数
\sum_{d \mid T}d*\mu(d)是个积性函数
∑d∣Td∗μ(d)是个积性函数
我们分析一下
设
h
(
T
)
=
∑
d
∣
T
d
∗
μ
(
d
)
h(T)=\sum_{d \mid T}d*\mu(d)
h(T)=∑d∣Td∗μ(d)
当
T
∈
p
r
i
m
e
T \in prime
T∈prime,
h
(
T
)
=
1
−
T
h(T)=1-T
h(T)=1−T
现有
x
=
i
∗
p
r
i
m
e
[
j
]
x=i*prime[j]
x=i∗prime[j]且i中无prime[j]这个质因子
h
(
i
∗
p
r
i
m
e
[
j
]
)
=
∑
d
∣
(
i
∗
p
r
i
m
e
[
j
]
)
d
∗
μ
(
d
)
h(i*prime[j])=\sum_{d \mid (i * prime[j])}d*\mu(d)
h(i∗prime[j])=∑d∣(i∗prime[j])d∗μ(d)
我们发现多了个质数会在原有约数的基础上翻一倍,并且一一对应
设z是i的约数,我们有
z
∗
p
r
i
m
e
[
j
]
∗
μ
(
z
∗
p
r
i
m
e
[
j
]
)
=
−
z
∗
μ
(
z
)
∗
p
r
i
m
e
[
j
]
z*prime[j]*\mu(z*prime[j])=-z*\mu(z)*prime[j]
z∗prime[j]∗μ(z∗prime[j])=−z∗μ(z)∗prime[j]
所以这一对的贡献就是
(
1
−
p
r
i
m
e
[
j
]
)
∗
z
∗
μ
(
z
)
(1-prime[j])*z*\mu(z)
(1−prime[j])∗z∗μ(z)
对于每一对我们都可以提出个
(
1
−
p
r
i
m
e
[
j
]
)
(1-prime[j])
(1−prime[j])
h
(
i
∗
p
r
i
m
e
[
j
]
)
=
h
(
i
)
∗
(
1
−
p
r
i
m
e
[
j
]
)
=
h
(
i
)
∗
h
(
p
r
i
m
e
[
j
]
)
h(i*prime[j])=h(i)*(1-prime[j])=h(i)*h(prime[j])
h(i∗prime[j])=h(i)∗(1−prime[j])=h(i)∗h(prime[j])
发现这玩意是个积性函数
如果
i
i
i中存在
p
r
i
m
e
[
j
]
prime[j]
prime[j]这个质因子
h
(
i
∗
p
r
i
m
e
[
j
]
)
=
∑
d
∣
(
i
∗
p
r
i
m
e
[
j
]
)
d
∗
μ
(
d
)
h(i*prime[j])=\sum_{d \mid (i * prime[j])}d*\mu(d)
h(i∗prime[j])=∑d∣(i∗prime[j])d∗μ(d)
对于d
如果d中有prime[j]这个质因子,我们会发现
μ
(
d
)
=
0
\mu(d)=0
μ(d)=0因为存在平方因子
如果d中无prime[j]这个质因子,我们会发现是
h
(
i
)
的
组
成
h(i)的组成
h(i)的组成
最后
h
(
i
∗
p
r
i
m
e
[
j
]
)
=
h
(
i
)
h(i*prime[j])=h(i)
h(i∗prime[j])=h(i)
这样我们可以用线性筛求出
h
(
T
)
h(T)
h(T)啦,那个T在求前缀和的时候乘上
那前面直接分块,时间复杂度降低到O(
n
\sqrt{n}
n)
筛法代码:
int gu[N], prime[N], tot;//gu为积性函数
bool mark[N];
void get_gu()
{
tot = 0;
mark[0] = mark[1] = true;
gu[1] = 1;
for(int i = 2; i < N; i ++)
{
if(!mark[i])
{
gu[i] = 1 - i;
prime[tot ++] = i;
}
for(int j = 0; j < tot && i * prime[j] < N; j ++)
{
mark[i * prime[j]] = true;
if(i % prime[j] == 0)
{
gu[i * prime[j]] = gu[i];
break;
}
gu[i * prime[j]] = gu[i] * (1 - prime[j]);
}
}
}
神仙的是我应该O(
n
\sqrt{n}
n)代码居然没我O(n)跑的快