整除分块入门
整除分块
首先引入一个问题,若我们要求这么一个式子:
∑
i
=
1
n
⌊
n
i
⌋
\sum\limits_{i=1}^{n} \left\lfloor\dfrac{n}{i}\right\rfloor
i=1∑n⌊in⌋
自然而然会想到这么一段翻译代码:
for(int i=1;i<=n;i++)
sum+=n/i;
但是,如果 1 ≤ n ≤ 1 0 9 1\le n\le10^9 1≤n≤109,又该如何解决呢?
显然,
⌊
n
i
⌋
\left\lfloor\dfrac{n}{i}\right\rfloor
⌊in⌋与
n
i
\dfrac{n}{i}
in的不同在于,前者的值在某些情况下会出现区间性的大量重复。
下面我们来考察当
n
=
10
n=10
n=10时
⌊
n
i
⌋
\left\lfloor\dfrac{n}{i}\right\rfloor
⌊in⌋的取值
10
5
3
2
2
1
1
1
1
1
\boxed{10}\quad \boxed{5}\quad \boxed{3}\quad \boxed{2\quad 2}\quad \boxed{1\quad 1\quad 1\quad 1\quad 1}
10532211111
我们可以发现:
⌊
n
1
⌋
=
10
⌊
n
2
⌋
=
5
⌊
n
3
⌋
=
3
⌊
n
4
⌋
=
⌊
n
5
⌋
=
2
⌊
n
6
⌋
=
⌊
n
7
⌋
=
⌊
n
8
⌋
=
⌊
n
9
⌋
=
⌊
n
10
⌋
=
1
\left\lfloor\dfrac{n}{1}\right\rfloor=10\\ ~\\ \left\lfloor\dfrac{n}{2}\right\rfloor=5\\ ~\\ \left\lfloor\dfrac{n}{3}\right\rfloor=3\\ ~\\ \left\lfloor\dfrac{n}{4}\right\rfloor=\left\lfloor\dfrac{n}{5}\right\rfloor=2\\ ~\\ \left\lfloor\dfrac{n}{6}\right\rfloor=\left\lfloor\dfrac{n}{7}\right\rfloor=\left\lfloor\dfrac{n}{8}\right\rfloor=\left\lfloor\dfrac{n}{9}\right\rfloor=\left\lfloor\dfrac{n}{10}\right\rfloor=1
⌊1n⌋=10 ⌊2n⌋=5 ⌊3n⌋=3 ⌊4n⌋=⌊5n⌋=2 ⌊6n⌋=⌊7n⌋=⌊8n⌋=⌊9n⌋=⌊10n⌋=1
显然重复部分(我们将他们成为块)占比很大,因此我们就找到了优化的突破口,如何优化在重复部分耗费的计算?
由于 i i i 单调递增排列,因此重复部分是连续出现的,对于一个块 [ l , r ] [l,r] [l,r],若求出了 l , r l,r l,r就可以快速计算一整个块整除意义上的贡献。
经过思考可以得到
l
l
l的初值必定为
1
1
1,还有一个很显然的
l
l
l 的转移方程:
l
=
r
+
1
l=r+1
l=r+1
此时问题再次简单化,如何在已知
l
l
l的情况下,快速求出重复部分右端点
r
r
r?
考虑
r
r
r的性质:根据
[
l
,
r
]
[l,r]
[l,r]的定义可以得到
⌊
n
l
⌋
=
⌊
n
r
⌋
\left\lfloor\dfrac{n}{l}\right\rfloor=\left\lfloor\dfrac{n}{r}\right\rfloor
⌊ln⌋=⌊rn⌋,我们将
⌊
n
l
⌋
\left\lfloor\dfrac{n}{l}\right\rfloor
⌊ln⌋表示为
k
k
k 。
此时有:
k
=
⌊
n
r
⌋
n
r
≥
k
(
向
下
取
整
必
定
小
于
分
数
运
算
)
r
n
≤
1
k
r
≤
⌊
n
k
⌋
(
r
∈
Z
)
k=\left\lfloor\dfrac{n}{r}\right\rfloor\\ ~\\ \dfrac{n}{r}\ge k~(向下取整必定小于分数运算)\\ ~\\ \dfrac{r}{n}\le \dfrac{1}{k}\\ ~\\ r\le \left\lfloor\dfrac{n}{k}\right\rfloor (r\in\Z)
k=⌊rn⌋ rn≥k (向下取整必定小于分数运算) nr≤k1 r≤⌊kn⌋(r∈Z)
此时若使
r
r
r 最大,则取等,即
r
=
⌊
n
k
⌋
=
⌊
n
⌊
n
l
⌋
⌋
r=\left\lfloor\dfrac{n}{k}\right\rfloor=\left\lfloor\dfrac{n}{\left\lfloor\dfrac{n}{l}\right\rfloor}\right\rfloor
r=⌊kn⌋=⎣⎢⎢⎢⌊ln⌋n⎦⎥⎥⎥
此时,我们已经得到了快速求出
l
,
r
l,r
l,r的算法,因此对于大量的重复贡献,我么可以利用
[
l
,
r
]
[l,r]
[l,r]区间快速得到总贡献,时间复杂度为
Θ
(
n
)
\Theta(\sqrt{n})
Θ(n)。
具体实现请看代码:
for(int l=1,r;l<=n;l=r+1)
{
int k=n/l;
r=n/k;
sum=sum+(k*(r-l+1)); //相同贡献乘区间长度
}
我们习惯把以上优化算法称为整除分块(或除法分块、数论分块等),它可以优化以下类似式子的时间复杂度:
∑
i
=
1
n
f
(
⌊
n
i
⌋
)
\sum\limits_{i=1}^{n}f(\left\lfloor\dfrac{n}{i}\right\rfloor)
i=1∑nf(⌊in⌋)
例题深化
1. UVA11526
模板题,翻译都不需要的那种,直接整除分块优化。(过~~~)
2.P3935 Calculating
题目大意:求
若
n
=
p
1
c
1
⋅
p
2
c
2
⋯
p
m
c
m
,
f
(
n
)
=
(
c
1
+
1
)
⋅
(
c
2
+
1
)
⋯
(
c
m
+
1
)
∑
i
=
l
r
f
(
i
)
m
o
d
998244353
若n=p_1^{c_1}\cdot p_2^{c_2}\cdots p_m^{c_m},f(n)=(c_1+1)\cdot(c_2+1)\cdots(c_m+1)\\ ~\\ \sum\limits_{i=l}^{r}f(i)~\bmod998244353\\
若n=p1c1⋅p2c2⋯pmcm,f(n)=(c1+1)⋅(c2+1)⋯(cm+1) i=l∑rf(i) mod998244353
首先我们要知道 n = p 1 c 1 ⋅ p 2 c 2 ⋯ p m c m , 则 f ( n ) = ( c 1 + 1 ) ⋅ ( c 2 + 1 ) ⋯ ( c m + 1 ) n=p_1^{c_1}\cdot p_2^{c_2}\cdots p_m^{c_m},则f(n)=(c_1+1)\cdot(c_2+1)\cdots(c_m+1) n=p1c1⋅p2c2⋯pmcm,则f(n)=(c1+1)⋅(c2+1)⋯(cm+1)即为 n n n的因数个数,可以由质因数的组合得到这个公式,这里不再详解。
回顾到这道题,要求区间 [ l , r ] [l,r] [l,r]中的数的因子个数之和,自然而然就是类似于前缀和式的方法:求出 [ 1 , l − 1 ] [1,l-1] [1,l−1]的因子和以及 [ 1 , r ] [1,r] [1,r]的因子和,然后后者减去前者,就可以得到 [ l , r ] [l,r] [l,r]的因子和。
可以知道, [ 1 , n ] [1,n] [1,n]中 i i i的倍数有 ⌊ n i ⌋ \left\lfloor\dfrac{n}{i}\right\rfloor ⌊in⌋个,即有 ⌊ n i ⌋ \left\lfloor\dfrac{n}{i}\right\rfloor ⌊in⌋个数包含因子 i i i。因此 ∑ i = 1 n f ( i ) = ∑ i = 1 n ⌊ n i ⌋ \sum\limits_{i=1}^{n}f(i)=\sum\limits_{i=1}^{n}\left\lfloor\dfrac{n}{i}\right\rfloor i=1∑nf(i)=i=1∑n⌊in⌋
∑ i = l r f ( i ) = ∑ i = 1 r ⌊ r i ⌋ − ∑ i = 1 l − 1 ⌊ l i ⌋ \sum\limits_{i=l}^{r}f(i)=\sum\limits_{i=1}^{r}\left\lfloor\dfrac{r}{i}\right\rfloor-\sum\limits_{i=1}^{l-1}\left\lfloor\dfrac{l}{i}\right\rfloor i=l∑rf(i)=i=1∑r⌊ir⌋−i=1∑l−1⌊il⌋
然后又变成了整除分块裸题。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int MOD=998244353;
int a,b;
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>a>>b;
int suma=0,sumb=0;
for(int l=1,r;l<=(a-1);l=r+1)
{
r=(a-1)/((a-1)/l);
suma=(suma+(((a-1)/l)%MOD*(r-l+1)%MOD)%MOD)%MOD;
}
for(int l=1,r;l<=b;l=r+1)
{
r=b/(b/l);
sumb=(sumb+((b/l)%MOD*(r-l+1)%MOD)%MOD)%MOD;
}
cout<<((sumb-suma)%MOD+MOD)%MOD;
return 0;
}
3.CF616E Sum of Remainders
题目大意:
求
(
∑
i
=
1
m
n
m
o
d
i
)
m
o
d
(
1
0
9
+
7
)
(\sum\limits_{i=1}^{m}n\bmod i)\bmod (10^9+7)
(i=1∑mnmodi)mod(109+7)
很简单的一道推式子题,就是因为用上了整除分块才水上了紫。
∑
i
=
1
m
n
m
o
d
i
=
∑
i
=
1
m
(
n
−
⌊
n
i
⌋
⋅
i
)
=
n
m
−
∑
i
=
1
m
⌊
n
i
⌋
⋅
i
\sum\limits_{i=1}^{m}n\bmod i=\sum\limits_{i=1}^{m}(n-\left\lfloor\dfrac{n}{i}\right\rfloor\cdot i)=nm-\sum\limits_{i=1}^{m}\left\lfloor\dfrac{n}{i}\right\rfloor\cdot i
i=1∑mnmodi=i=1∑m(n−⌊in⌋⋅i)=nm−i=1∑m⌊in⌋⋅i
由于块中的元素重复,我们可以提取公因数,因此乘
i
i
i可以在整除分块的过程中执行,不会影响效率,
∑
i
=
1
m
⌊
n
i
⌋
i
\sum\limits_{i=1}^{m}\left\lfloor\dfrac{n}{i}\right\rfloor i
i=1∑m⌊in⌋i可以利用整除分块和高斯求和公式快速得到(不懂得可以停下来稍微想想)。
照水不误
- 运算过程中会爆longlong,取余很恶心
- 在这种恶心超大取余数论题中,常要预处理出某些除数的乘法逆元。
#include <bits/stdc++.h>
#define int long long
#define inv2 500000004//2在mod 1e9+7 意义下的乘法逆元
using namespace std;
int n,m;
int ans;
const int MOD=1e9+7;
signed main()
{
cin>>n>>m;
ans=((n%MOD)*(m%MOD))%MOD;
int sum=0;
for(int l=1,r;l<=min(n,m);l=r+1)
{
r=n/(n/l);
if(r>m) r=m;
sum=(1ll*sum%MOD+(1ll*(n/l)%MOD*((((r-l+1)%MOD)*((r+l)%MOD))%MOD*inv2%MOD)%MOD)%MOD)%MOD;
}
cout<<((ans-sum%MOD)%MOD+MOD)%MOD;
return 0;
}
4.P2260 [清华集训2012]模积和
题目大意: 求
∑
i
=
1
n
∑
j
=
1
m
(
n
m
o
d
i
)
⋅
(
m
m
o
d
j
)
i
≠
j
\sum\limits_{i=1}^{n}\sum\limits_{j=1}^m(n\bmod i)\cdot(m\bmod j)~~i\ne j
i=1∑nj=1∑m(nmodi)⋅(mmodj) i=j
m
o
d
19940417
\bmod 19940417
mod19940417的值
对于这种式子很长,没有思路的题目,往往需要我们将式子拆开来才能找到考点。
考虑式子条件
i
≠
j
i\ne j
i=j的运算意义,就是在原有式子的基础上减去
i
,
j
i,j
i,j重复部分,即
∑
i
=
1
n
∑
j
=
1
m
(
n
m
o
d
i
)
(
m
m
o
d
j
)
−
∑
i
=
1
min
(
n
,
m
)
(
n
m
o
d
i
)
(
m
m
o
d
i
)
\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}(n \bmod i)(m\bmod j)-\sum\limits_{i=1}^{\min(n,m)}(n\bmod i)(m\bmod i)
i=1∑nj=1∑m(nmodi)(mmodj)−i=1∑min(n,m)(nmodi)(mmodi)
然后我们就可以愉快的手撕
∑
\sum
∑:
∑
i
=
1
n
∑
j
=
1
m
(
n
m
o
d
i
)
(
m
m
o
d
j
)
−
∑
i
=
1
min
(
n
,
m
)
(
n
m
o
d
i
)
(
m
m
o
d
i
)
⇔
∑
i
=
1
n
(
n
m
o
d
i
)
∑
j
=
1
m
(
m
m
o
d
j
)
−
∑
i
=
1
min
(
n
,
m
)
(
n
m
o
d
i
)
(
m
m
o
d
i
)
⇔
∑
i
=
1
n
(
n
m
o
d
i
)
∑
j
=
1
m
(
m
m
o
d
j
)
−
∑
i
=
1
min
(
n
,
m
)
(
n
−
⌊
n
i
⌋
⋅
i
)
(
m
−
⌊
m
i
⌋
⋅
i
)
⇔
∑
i
=
1
n
(
n
m
o
d
i
)
∑
j
=
1
m
(
m
m
o
d
j
)
−
∑
i
=
1
min
(
n
,
m
)
(
n
m
−
m
⋅
⌊
n
i
⌋
⋅
i
−
n
⋅
⌊
m
i
⌋
⋅
i
+
⌊
m
i
⌋
⌊
n
i
⌋
⋅
i
2
)
⇔
∑
i
=
1
n
(
n
m
o
d
i
)
∑
j
=
1
m
(
m
m
o
d
j
)
−
∑
i
=
1
min
(
n
,
m
)
n
m
+
∑
i
=
1
min
(
n
,
m
)
m
⌊
n
i
⌋
i
+
∑
i
=
1
min
(
n
,
m
)
n
⌊
m
i
⌋
i
−
∑
i
=
1
min
(
n
,
m
)
⌊
m
i
⌋
⌊
n
i
⌋
i
2
\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}(n \bmod i)(m\bmod j)-\sum\limits_{i=1}^{\min(n,m)}(n\bmod i)(m\bmod i)\\ \Leftrightarrow\\ \sum\limits_{i=1}^{n}(n\bmod i)\sum\limits_{j=1}^{m}(m\bmod j)-\sum\limits_{i=1}^{\min(n,m)}(n\bmod i)(m\bmod i)\\ \Leftrightarrow\\ \sum\limits_{i=1}^{n}(n\bmod i)\sum\limits_{j=1}^{m}(m\bmod j)-\sum\limits_{i=1}^{\min(n,m)}(n-\left\lfloor\dfrac{n}{i}\right\rfloor\cdot i)(m-\left\lfloor\dfrac{m}{i}\right\rfloor\cdot i)\\ \Leftrightarrow\\ \sum\limits_{i=1}^{n}(n\bmod i)\sum\limits_{j=1}^{m}(m\bmod j)-\sum\limits_{i=1}^{\min(n,m)}(nm-m\cdot\left\lfloor\dfrac{n}{i}\right\rfloor\cdot i-n\cdot\left\lfloor\dfrac{m}{i}\right\rfloor\cdot i+\left\lfloor\dfrac{m}{i}\right\rfloor\left\lfloor\dfrac{n}{i}\right\rfloor\cdot i^2)\\ \Leftrightarrow\\ \sum\limits_{i=1}^{n}(n\bmod i)\sum\limits_{j=1}^{m}(m\bmod j)-\sum\limits_{i=1}^{\min(n,m)}nm+\sum\limits_{i=1}^{\min(n,m)}m\left\lfloor\dfrac{n}{i}\right\rfloor i+\sum\limits_{i=1}^{\min(n,m)}n\left\lfloor\dfrac{m}{i}\right\rfloor i-\sum\limits_{i=1}^{\min(n,m)}\left\lfloor\dfrac{m}{i}\right\rfloor\left\lfloor\dfrac{n}{i}\right\rfloor i^2
i=1∑nj=1∑m(nmodi)(mmodj)−i=1∑min(n,m)(nmodi)(mmodi)⇔i=1∑n(nmodi)j=1∑m(mmodj)−i=1∑min(n,m)(nmodi)(mmodi)⇔i=1∑n(nmodi)j=1∑m(mmodj)−i=1∑min(n,m)(n−⌊in⌋⋅i)(m−⌊im⌋⋅i)⇔i=1∑n(nmodi)j=1∑m(mmodj)−i=1∑min(n,m)(nm−m⋅⌊in⌋⋅i−n⋅⌊im⌋⋅i+⌊im⌋⌊in⌋⋅i2)⇔i=1∑n(nmodi)j=1∑m(mmodj)−i=1∑min(n,m)nm+i=1∑min(n,m)m⌊in⌋i+i=1∑min(n,m)n⌊im⌋i−i=1∑min(n,m)⌊im⌋⌊in⌋i2
我们使
m
<
n
m<n
m<n:
∑
i
=
1
n
(
n
m
o
d
i
)
∑
j
=
1
m
(
m
m
o
d
j
)
−
∑
i
=
1
m
n
m
+
∑
i
=
1
m
m
⌊
n
i
⌋
i
+
∑
i
=
1
m
n
⌊
m
i
⌋
i
−
∑
i
=
1
m
⌊
m
i
⌋
⌊
n
i
⌋
i
2
⇔
∑
i
=
1
n
(
n
m
o
d
i
)
∑
j
=
1
m
(
m
m
o
d
j
)
−
n
m
2
+
m
∑
i
=
1
m
⌊
n
i
⌋
i
+
n
∑
i
=
1
m
⌊
m
i
⌋
i
−
∑
i
=
1
m
⌊
m
i
⌋
⌊
n
i
⌋
i
2
\sum\limits_{i=1}^{n}(n\bmod i)\sum\limits_{j=1}^{m}(m\bmod j)-\sum\limits_{i=1}^{m}nm+\sum\limits_{i=1}^{m}m\left\lfloor\dfrac{n}{i}\right\rfloor i+\sum\limits_{i=1}^{m}n\left\lfloor\dfrac{m}{i}\right\rfloor i-\sum\limits_{i=1}^{m}\left\lfloor\dfrac{m}{i}\right\rfloor\left\lfloor\dfrac{n}{i}\right\rfloor i^2\\ \Leftrightarrow\\ \sum\limits_{i=1}^{n}(n\bmod i)\sum\limits_{j=1}^{m}(m\bmod j)-nm^2+m\sum\limits_{i=1}^{m}\left\lfloor\dfrac{n}{i}\right\rfloor i+n\sum\limits_{i=1}^{m}\left\lfloor\dfrac{m}{i}\right\rfloor i-\sum\limits_{i=1}^{m}\left\lfloor\dfrac{m}{i}\right\rfloor\left\lfloor\dfrac{n}{i}\right\rfloor i^2
i=1∑n(nmodi)j=1∑m(mmodj)−i=1∑mnm+i=1∑mm⌊in⌋i+i=1∑mn⌊im⌋i−i=1∑m⌊im⌋⌊in⌋i2⇔i=1∑n(nmodi)j=1∑m(mmodj)−nm2+mi=1∑m⌊in⌋i+ni=1∑m⌊im⌋i−i=1∑m⌊im⌋⌊in⌋i2
这个式子结构性就很强了,我们可以考虑逐一求得式子各部分的值来得到最终答案。
-
part 1: ∑ i = 1 n ( n m o d i ) ∑ j = 1 m ( m m o d j ) \sum\limits_{i=1}^{n}(n\bmod i)\sum\limits_{j=1}^{m}(m\bmod j) i=1∑n(nmodi)j=1∑m(mmodj)
很显然就是上一题的结论与做法,不再赘述。 -
part 2: n m 2 nm^2 nm2
入门级运算 -
part 3: m ∑ i = 1 m ⌊ n i ⌋ i + n ∑ i = 1 m ⌊ m i ⌋ i m\sum\limits_{i=1}^m\left\lfloor\dfrac{n}{i}\right\rfloor i+n\sum\limits_{i=1}^{m}\left\lfloor\dfrac{m}{i}\right\rfloor i mi=1∑m⌊in⌋i+ni=1∑m⌊im⌋i
依旧是上一题结论,换汤不换药。 -
part 4: ∑ i = 1 m ⌊ m i ⌋ ⌊ n i ⌋ i 2 \sum\limits_{i=1}^{m}\left\lfloor\dfrac{m}{i}\right\rfloor\left\lfloor\dfrac{n}{i}\right\rfloor i^2 i=1∑m⌊im⌋⌊in⌋i2
看到这个式子我一开始就蒙了(太弱了),是不是式子柴得不够完全啊,然后就浪费了大量的时间来化简这个式子,最后还是做了无用功。
那到底应该如何处理呢?观察这部分式子, ⌊ m i ⌋ \left\lfloor\dfrac{m}{i}\right\rfloor ⌊im⌋与 ⌊ n i ⌋ \left\lfloor\dfrac{n}{i}\right\rfloor ⌊in⌋都是我们熟悉的整除分块,但是要是将他们联系在一起 ⌊ m i ⌋ ⌊ n i ⌋ \left\lfloor\dfrac{m}{i}\right\rfloor\left\lfloor\dfrac{n}{i}\right\rfloor ⌊im⌋⌊in⌋显然不是简单的直接分块相乘,那又该如何优化呢?借助上一题的思路,利用块的优化过程自然也要带上计算 i 2 i^2 i2,那是否 ∑ i = 1 n i 2 \sum\limits_{i=1}^{n}i^2 i=1∑ni2也具有类似等差数列一样的求和公式呢(我太弱了不知道,在教练的帮助下推了好久才推出来)?
我们来模拟一下 ∑ i = 1 m ⌊ m i ⌋ ⌊ n i ⌋ \sum\limits_{i=1}^{m}\left\lfloor\dfrac{m}{i}\right\rfloor\left\lfloor\dfrac{n}{i}\right\rfloor i=1∑m⌊im⌋⌊in⌋的过程,考虑 n = 20 , m = 17 n=20,m=17 n=20,m=17
20 ⋅ 17 10 ⋅ 8 6 ⋅ 5 5 ⋅ 4 4 ⋅ 3 3 ⋅ 2 2 ⋅ 2 2 ⋅ 2 2 ⋅ 1 2 ⋅ 1 1 ⋅ 1 1 ⋅ 1 1 ⋅ 1 1 ⋅ 1 1 ⋅ 1 1 ⋅ 1 1 ⋅ 1 \boxed{20\cdot 17}\quad\boxed{10\cdot 8}\quad\boxed{6\cdot5}\quad\boxed{5\cdot 4}\quad\boxed{4\cdot 3}\quad\boxed{3\cdot 2}\quad\boxed{2\cdot 2\quad 2\cdot 2}\quad\boxed{2\cdot 1\quad2\cdot 1}\\ ~\\ \boxed{1\cdot 1\quad1\cdot 1\quad1\cdot 1\quad1\cdot 1\quad1\cdot 1\quad1\cdot 1\quad1\cdot 1} 20⋅1710⋅86⋅55⋅44⋅33⋅22⋅22⋅22⋅12⋅1 1⋅11⋅11⋅11⋅11⋅11⋅11⋅1
稍加思索可以发现, ⌊ n i ⌋ \left\lfloor\dfrac{n}{i}\right\rfloor ⌊in⌋所分的一个块与 ⌊ m i ⌋ \left\lfloor\dfrac{m}{i}\right\rfloor ⌊im⌋所分的一个块的交集(公共部分)也是 ⌊ n i ⌋ ⌊ m i ⌋ \left\lfloor\dfrac{n}{i}\right\rfloor\left\lfloor\dfrac{m}{i}\right\rfloor ⌊in⌋⌊im⌋的一个块。
稍微数学一点的表达:
若
A
为
⌊
n
i
⌋
的
一
个
块
,
B
为
⌊
m
i
⌋
的
一
个
快
记
作
A
∈
⌊
n
i
⌋
,
B
∈
⌊
m
i
⌋
则
有
(
A
∩
B
)
∈
⌊
n
i
⌋
⌊
m
i
⌋
若A为\left\lfloor\dfrac{n}{i}\right\rfloor的一个块,B为\left\lfloor\dfrac{m}{i}\right\rfloor的一个快\\ ~\\ 记作~A\in\left\lfloor\dfrac{n}{i}\right\rfloor,B\in\left\lfloor\dfrac{m}{i}\right\rfloor\\ ~\\ 则有~(A\cap B)\in \left\lfloor\dfrac{n}{i}\right\rfloor\left\lfloor\dfrac{m}{i}\right\rfloor
若A为⌊in⌋的一个块,B为⌊im⌋的一个快 记作 A∈⌊in⌋,B∈⌊im⌋ 则有 (A∩B)∈⌊in⌋⌊im⌋
有了这个概念,我们就易得
⌊
n
i
⌋
⌊
m
i
⌋
\left\lfloor\dfrac{n}{i}\right\rfloor\left\lfloor\dfrac{m}{i}\right\rfloor
⌊in⌋⌊im⌋的块
[
l
,
r
]
[l,r]
[l,r]的左右端点转移方程:
{
r
=
min
(
⌊
n
⌊
n
l
⌋
⌋
,
⌊
m
⌊
m
l
⌋
⌋
)
l
=
r
+
1
\begin{cases} r=\min(\left\lfloor\dfrac{n}{\left\lfloor\dfrac{n}{l}\right\rfloor}\right\rfloor,\left\lfloor\dfrac{m}{\left\lfloor\dfrac{m}{l}\right\rfloor}\right\rfloor)\\ ~\\ l=r+1 \end{cases}
⎩⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎧r=min(⎣⎢⎢⎢⌊ln⌋n⎦⎥⎥⎥,⎣⎢⎢⎢⌊lm⌋m⎦⎥⎥⎥) l=r+1
接下来我们考虑推导 S n = ∑ i = 1 n i 2 S_n=\sum\limits_{i=1}^ni^2 Sn=i=1∑ni2 的通项式。
考虑
∵
(
n
+
1
)
3
=
n
3
+
3
n
2
+
3
n
+
1
∴
(
n
+
1
)
3
−
n
3
=
3
n
2
+
3
n
+
1
∴
{
2
3
−
1
3
=
3
⋅
1
2
+
3
+
1
=
7
3
3
−
2
3
=
3
⋅
2
2
+
3
⋅
2
+
1
=
19
4
3
−
3
3
=
3
⋅
3
2
+
3
⋅
3
+
1
=
37
⋯
(
n
+
1
)
3
−
n
3
=
3
n
2
+
3
n
+
1
∴
(
n
+
1
)
3
−
1
3
=
∑
i
=
1
n
(
(
i
+
1
)
3
−
i
3
)
=
3
∑
i
=
1
n
n
2
+
3
∑
i
=
1
n
i
+
∑
i
=
1
n
1
=
3
⋅
S
n
+
3
⋅
(
n
+
1
)
n
2
+
n
∴
S
n
=
(
n
+
1
)
3
3
−
1
3
−
(
n
+
1
)
n
2
−
n
3
=
2
(
n
+
1
)
3
6
−
2
6
−
3
(
n
+
1
)
n
6
−
2
n
6
=
2
(
n
+
1
)
3
−
2
−
3
(
n
+
1
)
n
−
2
n
6
=
2
n
3
+
6
n
2
+
6
n
+
2
−
2
−
3
n
2
−
3
n
−
2
n
6
=
2
n
3
+
3
n
2
+
n
6
=
n
(
n
+
1
)
(
2
n
+
1
)
6
(
提
取
公
因
数
后
再
十
字
相
乘
化
简
)
\because(n+1)^3=n^3+3n^2+3n+1\\ ~\\ \therefore(n+1)^3-n^3=3n^2+3n+1\\ ~\\ \therefore \begin{cases} 2^3-1^3=3\cdot 1^2+3+1=7\\ 3^3-2^3=3\cdot 2^2+3\cdot 2+1=19\\ 4^3-3^3=3\cdot3^2+3\cdot3+1=37\\ \cdots\\ (n+1)^3-n^3=3n^2+3n+1 \end{cases}\\ ~\\ \therefore\begin{aligned} (n+1)^3-1^3&=\sum\limits_{i=1}^{n}\left((i+1)^3-i^3\right)\\ &=3\sum\limits_{i=1}^{n}n^2+3\sum\limits_{i=1}^{n}i+\sum\limits_{i=1}^n1\\ &=3\cdot S_n+3\cdot\dfrac{(n+1)n}{2}+n \end{aligned}\\ \therefore\begin{aligned} S_n&=\dfrac{(n+1)^3}{3}-\dfrac{1}{3}-\dfrac{(n+1)n}{2}-\dfrac{n}{3}\\ &=\dfrac{2(n+1)^3}{6}-\dfrac{2}{6}-\dfrac{3(n+1)n}{6}-\dfrac{2n}{6}\\ &=\dfrac{2(n+1)^3-2-3(n+1)n-2n}{6}\\ &=\dfrac{2n^3+6n^2+6n+2-2-3n^2-3n-2n}{6}\\ &=\dfrac{2n^3+3n^2+n}{6}\\ &=\dfrac{n(n+1)(2n+1)}{6}~~~~(提取公因数后再十字相乘化简)\\ \end{aligned}
∵(n+1)3=n3+3n2+3n+1 ∴(n+1)3−n3=3n2+3n+1 ∴⎩⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎧23−13=3⋅12+3+1=733−23=3⋅22+3⋅2+1=1943−33=3⋅32+3⋅3+1=37⋯(n+1)3−n3=3n2+3n+1 ∴(n+1)3−13=i=1∑n((i+1)3−i3)=3i=1∑nn2+3i=1∑ni+i=1∑n1=3⋅Sn+3⋅2(n+1)n+n∴Sn=3(n+1)3−31−2(n+1)n−3n=62(n+1)3−62−63(n+1)n−62n=62(n+1)3−2−3(n+1)n−2n=62n3+6n2+6n+2−2−3n2−3n−2n=62n3+3n2+n=6n(n+1)(2n+1) (提取公因数后再十字相乘化简)
此时,我们已经解决了关于这道题的所有难点,有了二维整除分块以及 ∑ i = 1 n i 2 \sum\limits_{i=1}^ni^2 i=1∑ni2的求和公式,我么就可仿照类似上一题一般的方法优化 ∑ i = 1 m ⌊ n i ⌋ ⌊ m i ⌋ i 2 \sum\limits_{i=1}^m\left\lfloor\dfrac{n}{i}\right\rfloor\left\lfloor\dfrac{m}{i}\right\rfloor i^2 i=1∑m⌊in⌋⌊im⌋i2。
此时,我们首先化简题目的式子,然后对式子各部分进行逐一处理优化,最后得到了最终的算法:
处理以下函数
- F x : ∑ i = 1 x ( x m o d i ) F_x:\sum\limits_{i=1}^x(x\bmod i) Fx:i=1∑x(xmodi)
- G x , y : ∑ i = 1 x ( y m o d i ) G_{x,y} :\sum\limits_{i=1}^x(y\bmod i) Gx,y:i=1∑x(ymodi)
- T : ∑ i = 1 m ⌊ n i ⌋ ⌊ m i ⌋ i 2 T:\sum\limits_{i=1}^m\left\lfloor\dfrac{n}{i}\right\rfloor\left\lfloor\dfrac{m}{i}\right\rfloor i^2 T:i=1∑m⌊in⌋⌊im⌋i2
最终答案为: F n F m − n m 2 + n G m , m + m G m , n − T F_nF_m-nm^2+nG_{m,m}+mG_{m,n}-T FnFm−nm2+nGm,m+mGm,n−T
#include<bits/stdc++.h>
#define int long long
const long long MOD=19940417,inv6=3323403,inv2=9970209; //预处理公式中除数的乘法逆元
using namespace std;
int n,m;
int G(int s,int t)
{
int sum=0;
for(int l=1,r;l<=s;l=r+1)
{
r=min(t/(t/l),s);
sum=(sum+1ll*(t/l)*(r+l)%MOD*(r-l+1)%MOD*inv2)%MOD;
}
return sum%MOD;
}
int F(int s)
{
return (1ll*s*s-G(s,s))%MOD;
}
int S(int s)
{
return 1ll*s*(s+1)%MOD*(s+s+1)%MOD*inv6%MOD;
}
int ans()
{
int a;
a=1ll*F(n)*F(m)%MOD;
a=(a+1ll*n*G(m,m)+1ll*m*G(m,n))%MOD;
a=1ll*(a-1ll*m*m%MOD*n)%MOD;
return a;
}
int T()
{
int sum=ans();
for(int l=1,r;l<=m;l=r+1)
{
r=min(n/(n/l),m/(m/l));
sum=(sum-1ll*((n/l)%MOD*(m/l))%MOD*(S(r)-S(l-1))%MOD)%MOD;
}
return (sum%MOD+MOD)%MOD;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
if(m>n) swap(m,n);
cout<<T();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!