整除分块学习笔记

复习一下我本就不多的数论芝士()

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\le\dfrac{n}{r}<k+1 \]

\[\dfrac{n}{k+1}<r\le\dfrac{n}{k} \]

\(k=\left\lfloor\dfrac{n}{l}\right\rfloor\) 带入 得

\[\dfrac{n}{\left\lfloor\dfrac{n}{l}\right\rfloor+1}<r\le\dfrac{n}{\left\lfloor\dfrac{n}{l}\right\rfloor} \]

\[\therefore max_r=\left\lfloor\dfrac{n}{\left\lfloor\dfrac{n}{l}\right\rfloor}\right\rfloor \]

例题:UVA11526 H(n)

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;
}
posted @ 2023-09-27 10:45  xiang_xiang  阅读(23)  评论(0)    收藏  举报