一、 基本思想
对于形如 (sum_{i=1}^n f(lfloor frac{n}{i} floor)) 的式子,先不考虑求 (f(lfloor frac{n}{i} floor)) 的复杂度,则若采用朴素的解法,时间复杂度为 (O(n))。
简便起见,我们令 (f(lfloorfrac{n}{i} floor)=lfloor frac{n}{i} floor)。
打表找规律可以发现,(lfloor frac{n}{i} floor) 的取值并没有 (n) 个,且在一定区域内相等,呈块状阶梯分布。
对于每一个块,假设它的左端点为 (l),右端点为 (r),对于 (forall iin[l,r]),(lfloorfrac{n}{i} floor) 的值都相等。那么我们只需要求出,每一个块的左端点和右端点,以及块内的值即可。
二、 具体实现
Part 1. 块的数量
对于任意整数 (i) 满足 (1leq ileq n),(lfloorfrac{n}{i} floor) 最多只有 (2sqrt{n}) 个不同的值。因为:
-
当 (ileq sqrt{n}) 时,(i) 只有 (sqrt{n}) 种选择,故 (lfloorfrac{n}{i} floor) 至多只有 (sqrt{n}) 个不同的值。
-
当 (i>sqrt{n}) 时,(lfloorfrac{n}{i} floor < sqrt{n}),故 (lfloorfrac{n}{i} floor) 也至多只有 (sqrt{n}) 个不同的值。
综上所述,对于 (i=1sim n),(lfloorfrac{n}{i} floor < sqrt{n}) 由不超过 (2sqrt{n}) 个块组成。
Part 2. 块的左右端点
对于任意一个 (i)((ileq n)),我们需要找到一个最大的 (x)((ileq xleq n)),使得 (lfloorfrac{n}{i} floor=lfloorfrac{n}{x} floor)。
此时 (x=lfloorfrac{n}{lfloorfrac{n}{i} floor} floor)。如下所述:
-
显然 (xleq n),考虑证明 (xgeq i)。
证明:因为 (lfloorfrac{n}{i} floorleq frac{n}{i}),所以 (lfloorfrac{n}{lfloorfrac{n}{i} floor} floor geq lfloorfrac{n}{frac{n}{i}} floor=lfloor i floor=i)。则 (ileq lfloorfrac{n}{lfloorfrac{n}{i} floor} floor =x)。证毕。 -
不妨设 (k=lfloorfrac{n}{i} floor),考虑证明当 (lfloorfrac{n}{x} floor=k) 时,(x) 的最大值为 (lfloorfrac{n}{k} floor)。
证明:(lfloorfrac{n}{x} floor=k),等价于 (kleq frac{n}{x}<k+1),那么 (frac{1}{k+1}<frac{x}{n}leq frac{1}{k}),则 (frac{n}{k+1}<xleq frac{n}{k})。又因为 (x) 为整数,所以,(x_{max}=lfloorfrac{n}{k} floor)。证毕。
每一块 (iin[x,lfloorfrac{n}{lfloor frac{n}{x} floor} floor]) 中 (lfloor frac{n}{i} floor) 的值都等于 (lfloorfrac{n}{x} floor)。
对于每一个块,假设它的左端点为 (l),则它的右端点为 (lfloorfrac{n}{lfloorfrac{n}{l} floor} floor),并且块内元素都为 (lfloorfrac{n}{l} floor)。
注意:有时需要考虑 (lfloor frac{k}{l} floor=0) 的情况。
时间复杂度:(mathcal{O}(sqrt{n}))。
#include<bits/stdc++.h> #define int long long using namespace std; int n,ans; signed main(){ scanf("%lld",&n); for(int l=1,r=0;l<=n;l=r+1) //l 为块的左端点,r 为块的右端点 r=n/(n/l),ans+=(r-l+1)*(n/l); //块的大小为 r-l+1,块内元素的值都为 n/l 下取整,则整个块的元素之和为 (r-l+1)*(n/l) printf("%lld ",ans); return 0; }
Expand. 二维整除分块
求 (sum_{i=1}^{min(n,m)} lfloorfrac{n}{i} floor lfloorfrac{m}{i} floor)。
此时可将代码中 r=n/(n/l)
替换成 r=min(n/(n/l),m/(m/l))
。
#include<bits/stdc++.h> #define int long long using namespace std; int n,m,ans; signed main(){ scanf("%lld%lld",&n,&m); for(int l=1,r=0;l<=min(n,m);l=r+1){ r=min(n/(n/l),m/(m/l)); ans+=(r-l+1)*(n/l)*(m/l); } printf("%lld ",ans); return 0; }
三、例题
1. Luogu P2261 [CQOI2007]余数求和
题目大意:给出正整数 (n) 和 (k),求 (sum_{i=1}^n k mod i) 的值。(1leq n,kleq 10^9)。
Solution:
注意到 (kmod i=k-lfloor frac{k}{i} floor imes i),所以 (sum_{i=1}^n k mod i=sum_{i=1}^n k-sum_{i=1}^nlfloor frac{k}{i} floor imes i)(=n imes k-sum_{i=1}^nlfloor frac{k}{i} floor imes i)。
考虑整除分块,对于每一个块,假设它的左端点为 (l),右端点为 (r),则对于 (forall iin[l,r]),(lfloor frac{k}{i} floor imes i=lfloor frac{k}{l} floor imes i),直接用等差数列求和公式计算即可。
注意 (lfloor frac{k}{l} floor=0) 的情况。
#include<bits/stdc++.h> #define int long long using namespace std; int n,k,ans; signed main(){ scanf("%lld%lld",&n,&k); for(int l=1,r=0;l<=n;l=r+1) r=k/l==0?n:min(k/(k/l),n),ans+=(k/l)*((l+r)*(r-l+1)/2); //注意这里 k/(k/l) 可能会超过 n,所以需要取 min。 printf("%lld ",n*k-ans); return 0; }
2. Luogu P3935 Calculating
题目大意:若 (x) 分解质因数结果为 (x=p_1^{k_1}p_2^{k_2}cdots p_n^{k_n}),令 (f(x)=(k_1+1)(k_2+1)cdots (k_n+1)),求 (sum_{i=l}^rf(i)) 对 (998244353) 取模的结果。(1leq lleq 10^{14},1leq rleq 1.6 imes 10^{14},r-l>10^{14})。
Solution:
根据唯一分解定理,可得:(n=p_1^{c_1} imes p_2^{c_2} imes cdots imes p_k^{c_k}=prodlimits_{i=1}^kp_i^{c_i})。
(p_i^{c_i}) 的约数有 (p_i^0,p_i^1,cdots,p_i^{c_i}) 共 (c_i+1) 个,根据乘法原理,可得 (n) 的约数个数为 (d(n)=prodlimits_{i=1}^k (c_i+1))。
容易得出,(f(n)) 实际上就是 (n) 的约数个数。
令 (S(n)=sum_{i=1}^n f(i)),则 (sum_{i=l}^r f(i)=S(r)-S(l-1))。
(S(n)=sum_{i=1}^n sum_{dmid i} 1=sum_{d=1}^nlfloor frac{n}{d} floor)。然后就可以用整除分块求了。
#include<bits/stdc++.h> #define int long long using namespace std; const int mod=998244353; int l,r,ans; int query(int n){ //求 S(n) int ans=0; for(int l=1,r=0;l<=n;l=r+1) r=n/(n/l),ans=(ans+(r-l+1)*(n/l)%mod)%mod; return ans; } signed main(){ scanf("%lld%lld",&l,&r); printf("%lld ",(query(r)-query(l-1)+mod)%mod); return 0; }
四、习题
- Luogu P2260 [清华集训2012]模积和