整除分块学习笔记
复习一下我本就不多的数论芝士()
1.取值数量
对于 \(\left\lfloor\dfrac{n}{i}\right\rfloor\) 最多只会有 \(2\sqrt{n}\) 种取值
1.当 \(1\le i \le\sqrt{n}\) 时 \(i\) 只有 \(\sqrt{n}\) 种取值 \(\left\lfloor\dfrac{n}{i}\right\rfloor\) 也只有 \(\sqrt{n}\) 种取值
2.当 \(\sqrt{n}< i \le n\) 时 \(\left\lfloor\dfrac{n}{\sqrt{n}}\right\rfloor=\sqrt{n}\quad\left\lfloor\dfrac{n}{n}\right\rfloor=1\)
所以\(\left\lfloor\dfrac{n}{i}\right\rfloor\in\left[1,\sqrt{n}\right]\quad\left\lfloor\dfrac{n}{i}\right\rfloor\)一定只有\(\sqrt{n}\) 种取值
3.当 \(i>n\) 时 \(\left\lfloor\dfrac{n}{i}\right\rfloor=0\)
因此枚举 \(\left\lfloor\dfrac{n}{i}\right\rfloor\) 我们可以在 \(O(\sqrt{n})\) 复杂度内完成
我们可以把 \(\left\lfloor\dfrac{n}{i}\right\rfloor\) 每一种取值 \(i\) 的范围当成一块
即 \(\left\lfloor\dfrac{n}{l}\right\rfloor=\left\lfloor\dfrac{n}{l+1}\right\rfloor=...=\left\lfloor\dfrac{n}{r-1}\right\rfloor=\left\lfloor\dfrac{n}{r}\right\rfloor\)
2.范围
我们考虑如何从前一块推出下一块
首先 显然的是 当前块的 \(l\) \(=\) 上一块的\(r\ +1\)
那么我们只要考虑怎么从当前块的 \(l\) 推出 \(r\) 即可
先放出结论:\(r=\left\lfloor\dfrac{n}{\left\lfloor\dfrac{n}{l}\right\rfloor}\right\rfloor\)
证明:
设 \(k=\left\lfloor\dfrac{n}{l}\right\rfloor\) (则 \(k\) 为本块的值 \(\ k+1\) 是下一块的值)
把 \(k=\left\lfloor\dfrac{n}{l}\right\rfloor\) 带入 得
code:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inl inline
#define int ll
const int N=5e5+5;
const int inf=INT_MAX;
const int mod=1e9+7;
inl int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return x*f;
}
inl void write(int x){
if(x<0){putchar('-');x=-x;}
if(x>9)write(x/10);
putchar(x%10+'0');
}
inl void writel(int x){write(x);putchar('\n');}
int t,n,k,ans;
signed main(){
t=read();
while(t--){
n=read();ans=0;
int l=1,r;
while(l<=n){
r=min(n,n/(n/l));
ans+=(r-l+1)*(n/l);
l=r+1;
}
writel(ans);
}
return 0;
}

浙公网安备 33010602011771号