整除分块 学习笔记

过程

用来求求和符号内带有 \(\lfloor\frac{n}{i}\rfloor\) 的式子,例如 \(\sum_{i=1}^n f(i)\lfloor\frac{n}{i}\rfloor\)

不难发现 \(\lfloor\frac{n}{i}\rfloor\) 的取值是成段的。当 \(i\leq\sqrt n\),取值不超过 \(\sqrt n\) 种,当 \(i>\sqrt n\)\(\lfloor\frac{n}{i}\rfloor\leq\sqrt n\)。因此总取值是根号级别的。

假设已知块左端点 \(l\),推出右端点 \(r\),在区间 \([l,r]\)\(\lfloor\frac n i\rfloor\) 是相同的,那么式子就变成 \(\sum_{(l,r)}\lfloor\frac{n}{i}\rfloor\sum_{i=l}^rf(i)\),只需要快速计算 \(f\) 的前缀和即可。

引理:

现在推一下 \(r\)

\[\begin{aligned}\lfloor\frac n l\rfloor&=\lfloor\frac n r\rfloor\\\lfloor\frac n l\rfloor&\leq\frac n r\\r&\leq\frac{n}{\lfloor\frac{n}{l}\rfloor}\end{aligned} \]

因此 \(r=\lfloor\frac{n}{\lfloor\frac{n}{l}\rfloor}\rfloor\)

for(int l=1,r;l<=n;l=r+1)r=n/(n/l),ans+=sum(l,r)*(n/l);

P2261

\(\sum_{i=1}^n k\bmod i\)

推式子:

\[\begin{aligned}\sum_{i=1}^n k\bmod i&=\sum_{i=1}^n k-\lfloor\frac{k}{i}\rfloor i\text{($\bmod$ 的定义)}\\&=nk-\sum_{i=1}^n \lfloor\frac{k}{i}\rfloor i\\&=nk-\sum_{(l,r)}(\sum_{i=l}^ri)\lfloor\frac{k}{i}\rfloor\\&=nk-\sum_{(l,r)}\frac{(l+r)(r-l+1)}{2}\lfloor\frac{k}{i}\rfloor\end{aligned} \]

由于分子不到 \(n\),可能出现 \(\lfloor\frac{k}{l}\rfloor\)\(0\),这样算 \(r\) 的时候会寄掉,此时直接给 \(r\) 赋值为 \(n\)

#include<bits/stdc++.h>
using namespace std;
long long n,k,ans;
int main(){
  cin>>n>>k;
  for(long long l=1,r;l<=n;l=r+1)r=k/l?min(n,k/(k/l)):n,ans+=(k/l)*(r-l+1)*(l+r)/2;
  return cout<<n*k-ans<<'\n',0;
}

高维整除分块

假如求和符号内同时有 \(\lfloor\frac{n}{i}\rfloor,\lfloor\frac{m}{i}\rfloor\),如果用整除分块,需要使得 区间 \([l,r]\)\(\lfloor\frac{n}{i}\rfloor,\lfloor\frac{m}{i}\rfloor\) 都相等。此时,只需要让 \(r=\min(\lfloor\frac{n}{\lfloor\frac{n}{l}\rfloor}\rfloor,\lfloor\frac{m}{\lfloor\frac{m}{l}\rfloor}\rfloor)\) 即可。更高维类似。

复杂度证明:每一维一共有 \(O(\sqrt n)\) 个分界点,加在一起仍然是 \(O(\sqrt n)\) 个分界点。

P2260

推式子:

\[\begin{aligned}&\sum_{i=1}^n\sum_{j=1}^m(n\bmod i)(m\bmod j),i\ne j\\&=\sum_{i=1}^n(n\bmod i)\cdot\sum_{j=1}^m(m\bmod j)b-\sum_{i=1}^n(n\bmod i)\cdot(m\bmod i)\\&=\sum_{i=1}^n(n-\lfloor\frac n i\rfloor\cdot i)\cdot\sum_{j=1}^m(m-\lfloor\frac m j\rfloor\cdot j)b-\sum_{i=1}^n(n-\lfloor\frac n i\rfloor\cdot i)\cdot(m-\lfloor\frac m i\rfloor\cdot i)\text{($\bmod$ 的定义)}\\&=(n^2-\sum_{i=1}^n\lfloor\frac n i\rfloor\cdot i)(m^2-\sum_{i=1}^m\lfloor\frac m i\rfloor\cdot i)-\sum_{i=1}^{\min(n,m)}(nm-\lfloor\frac n i\rfloor\cdot mi-\lfloor\frac m i\rfloor\cdot ni+\lfloor\frac n i\rfloor\cdot\lfloor\frac m i\rfloor\cdot i^2)\end{aligned} \]

其中每部分都可以通过整除分块快速算。

#include<bits/stdc++.h>
using namespace std;
const long long mod=19940417;
long long n,m,t1,t2,t3;
int main(){
  cin>>n>>m,t1=n*n%mod,t2=m*m%mod;
  for(long long l=1,r;l<=n;l=r+1)r=n/(n/l),t1=(t1-(l+r)*(r-l+1)%mod*9970209%mod*(n/l)%mod+mod)%mod;
  for(long long l=1,r;l<=m;l=r+1)r=m/(m/l),t2=(t2-(l+r)*(r-l+1)%mod*9970209%mod*(m/l)%mod+mod)%mod;
  for(long long l=1,r;l<=min(n,m);l=r+1){
    r=min(n/(n/l),m/(m/l));
    t3=(t3+(r-l+1)*n%mod*m%mod)%mod;
    t3=(t3-(l+r)*(r-l+1)%mod*9970209%mod*((n/l)*m%mod+(m/l)*n%mod)%mod+mod)%mod;
    t3=(t3+(n/l)*(m/l)%mod*(r*(r+1)%mod*(2*r+1)%mod-(l-1)*l%mod*(2*l-1)%mod+mod)%mod*3323403%mod)%mod;
  }
  return cout<<(t1*t2%mod-t3+mod)%mod<<'\n',0;
}

高次整除分块

形如 \(\lfloor\frac{n}{i^k}\rfloor\) 的式子都可整除分块,取值共 \(\sqrt[k+1]{n}\) 种。此时右端点 \(r\) 为:

\[\begin{aligned}\lfloor\frac n{l^k}\rfloor&=\lfloor\frac n{r^k}\rfloor\\\lfloor\frac n{l^k}\rfloor&\leq\frac n{r^k}\\r^k&\leq\frac n{\lfloor\frac n{l^k}\rfloor}\\r&=\left\lfloor\sqrt[k]{\left\lfloor\frac n{\lfloor\frac n{l^k}\rfloor}\right\rfloor}\right\rfloor\\\end{aligned} \]

[[数学]]

posted @ 2024-03-01 09:35  lgh_2009  阅读(12)  评论(0)    收藏  举报