整除分块 — 洛谷P2261 [CQOI2007]余数求和

什么是整除分块

蒟蒻通过一个很有趣的问题学到了整除分块

∑ i = 1 n ⌊ n i ⌋ , n ≤ 1 0 12 \sum_{i=1}^n\lfloor\frac{n}{i}\rfloor,n\leq 10^{12} i=1nin,n1012

直接线性求肯定会超,但是我们冷静分(da)析(biao)一波
会发现这样两个性质

  • ∀ i ∈ [ 1 , n ] , ⌊ n i ⌋ \forall i\in[1,n],\lfloor\frac{n}{i}\rfloor i[1,n],in至多只有 2 n 2\sqrt n 2n 个不同的值

因为 n n n的约数是以 n \sqrt n n 对称的,这点不难证明
对于 i < = n i<=\sqrt n i<=n ⌊ n i ⌋ \lfloor\frac{n}{i}\rfloor in至多只有 n \sqrt n n 个不同的值,同理对于 i ≥ n i\geq\sqrt n in 也一样

  • ⌊ n i ⌋ = ⌊ n i ′ ⌋ \lfloor\frac{n}{i}\rfloor=\lfloor\frac{n}{i^{'}}\rfloor in=in,则 i ′ i^{'} i最大值为 ⌊ n ⌊ n i ⌋ ⌋ \lfloor\frac{n}{\lfloor\frac{n}{i}\rfloor}\rfloor inn

暂时不会证

根据上述性质,这个问题的复杂度下降为 O ( n ) O(\sqrt n) O(n )

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

整除分块的应用

BZOJ1257 || 洛谷P2261 [CQOI2007]余数求和

典型的整除分块
∑ i = 1 n k m o d    i = ∑ i = 1 n k − i ∗ ⌊ k i ⌋ = n ∗ k − i ∗ ⌊ k i ⌋ \sum_{i=1}^nk\mod i=\sum_{i=1}^nk-i*\lfloor\frac{k}{i}\rfloor=n*k-i*\lfloor\frac{k}{i}\rfloor i=1nkmodi=i=1nkiik=nkiik

#include
#include
#include
#include
#include
using namespace std;
typedef long long lt;
  
lt read()
{
    lt f=1,x=0;
    char ss=getchar();
    while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
    while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
    return f*x;
}

lt n,k;

int main()
{
    n=read();k=read();
    lt ans=n*k;
    for(lt ll=1,rr;ll<=n;ll=rr+1) 
    {
        if(k/ll!=0) rr=min(k/(k/ll),n); 
        else rr=n;
        ans-=(rr-ll+1)*(k/ll)*(ll+rr)/2;
    }
    printf("%lld",ans);
    return 0;
}

其实整除分块一般经常与前缀和等一同出现
莫比乌斯反演的题应用比较广泛

你可能感兴趣的:(数学;数论)