一、 基本思想

对于形如 \(\sum_{i=1}^n f(\lfloor \frac{n}{i}\rfloor)\) 的式子,先不考虑求 \(f(\lfloor \frac{n}{i}\rfloor)\) 的复杂度,则若采用朴素的解法,时间复杂度为 \(O(n)\)

简便起见,我们令 \(f(\lfloor\frac{n}{i}\rfloor)=\lfloor \frac{n}{i}\rfloor\)

打表找规律可以发现,\(\lfloor \frac{n}{i}\rfloor\) 的取值并没有 \(n\) 个,且在一定区域内相等,呈块状阶梯分布

对于每一个块,假设它的左端点为 \(l\),右端点为 \(r\),对于 \(\forall i\in[l,r]\)\(\lfloor\frac{n}{i}\rfloor\) 的值都相等。那么我们只需要求出,每一个块的左端点和右端点,以及块内的值即可。

二、 具体实现

Part 1. 块的数量

对于任意整数 \(i\) 满足 \(1\leq i\leq n\)\(\lfloor\frac{n}{i}\rfloor\) 最多只有 \(2\sqrt{n}\) 个不同的值。因为:

  • \(i\leq \sqrt{n}\) 时,\(i\) 只有 \(\sqrt{n}\) 种选择,故 \(\lfloor\frac{n}{i}\rfloor\) 至多只有 \(\sqrt{n}\) 个不同的值。

  • \(i>\sqrt{n}\) 时,\(\lfloor\frac{n}{i}\rfloor < \sqrt{n}\),故 \(\lfloor\frac{n}{i}\rfloor\) 也至多只有 \(\sqrt{n}\) 个不同的值。

综上所述,对于 \(i=1\sim n\)\(\lfloor\frac{n}{i}\rfloor < \sqrt{n}\) 由不超过 \(2\sqrt{n}\) 个块组成。

Part 2. 块的左右端点

对于任意一个 \(i\)\(i\leq n\)),我们需要找到一个最大的 \(x\)\(i\leq x\leq n\)),使得 \(\lfloor\frac{n}{i}\rfloor=\lfloor\frac{n}{x}\rfloor\)

此时 \(x=\lfloor\frac{n}{\lfloor\frac{n}{i}\rfloor}\rfloor\)。如下所述:

  • 显然 \(x\leq n\),考虑证明 \(x\geq i\)
    证明:因为 \(\lfloor\frac{n}{i}\rfloor\leq \frac{n}{i}\),所以 \(\lfloor\frac{n}{\lfloor\frac{n}{i}\rfloor}\rfloor \geq \lfloor\frac{n}{\frac{n}{i}}\rfloor=\lfloor i\rfloor=i\)。则 \(i\leq \lfloor\frac{n}{\lfloor\frac{n}{i}\rfloor}\rfloor =x\)。证毕。

  • 不妨设 \(k=\lfloor\frac{n}{i}\rfloor\),考虑证明当 \(\lfloor\frac{n}{x}\rfloor=k\) 时,\(x\) 的最大值为 \(\lfloor\frac{n}{k}\rfloor\)
    证明:\(\lfloor\frac{n}{x}\rfloor=k\),等价于 \(k\leq \frac{n}{x}<k+1\),那么 \(\frac{1}{k+1}<\frac{x}{n}\leq \frac{1}{k}\),则 \(\frac{n}{k+1}<x\leq \frac{n}{k}\)。又因为 \(x\) 为整数,所以,\(x_{\max}=\lfloor\frac{n}{k}\rfloor\)。证毕。

每一块 \(i\in[x,\lfloor\frac{n}{\lfloor \frac{n}{x} \rfloor}\rfloor]\)\(\lfloor \frac{n}{i}\rfloor\) 的值都等于 \(\lfloor\frac{n}{x}\rfloor\)

对于每一个块,假设它的左端点为 \(l\),则它的右端点为 \(\lfloor\frac{n}{\lfloor\frac{n}{l}\rfloor}\rfloor\),并且块内元素都为 \(\lfloor\frac{n}{l}\rfloor\)

注意:有时需要考虑 \(\lfloor \frac{k}{l}\rfloor=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\n",ans);
    return 0;
}

Expand. 二维整除分块

\(\sum_{i=1}^{\min(n,m)} \lfloor\frac{n}{i}\rfloor \lfloor\frac{m}{i}\rfloor\)

此时可将代码中 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\n",ans);
    return 0;
}

三、例题

1. Luogu P2261 [CQOI2007]余数求和

题目大意:给出正整数 \(n\)\(k\),求 \(\sum_{i=1}^n k \bmod i\) 的值。\(1\leq n,k\leq 10^9\)

Solution:

注意到 \(k\bmod i=k-\lfloor \frac{k}{i} \rfloor \times i\),所以 \(\sum_{i=1}^n k \bmod i=\sum_{i=1}^n k-\sum_{i=1}^n\lfloor \frac{k}{i} \rfloor \times i\)\(=n\times k-\sum_{i=1}^n\lfloor \frac{k}{i} \rfloor \times i\)

考虑整除分块,对于每一个块,假设它的左端点为 \(l\),右端点为 \(r\),则对于 \(\forall i\in[l,r]\)\(\lfloor \frac{k}{i}\rfloor \times i=\lfloor \frac{k}{l}\rfloor \times i\),直接用等差数列求和公式计算即可。

注意 \(\lfloor \frac{k}{l}\rfloor=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",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\) 取模的结果。\(1\leq l\leq 10^{14},1\leq r\leq 1.6\times 10^{14},r-l>10^{14}\)

Solution:

根据唯一分解定理,可得:\(n=p_1^{c_1}\times p_2^{c_2}\times \cdots \times p_k^{c_k}=\prod\limits_{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)=\prod\limits_{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_{d\mid i} 1=\sum_{d=1}^n\lfloor \frac{n}{d}\rfloor\)。然后就可以用整除分块求了。

#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\n",(query(r)-query(l-1)+mod)%mod);
    return 0;
}

四、习题

  • Luogu P2260 [清华集训2012]模积和

相关文章:

  • 2021-12-22
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2022-12-23
  • 2022-02-23
  • 2022-12-23
  • 2022-12-23
  • 2021-06-17
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案