整除分块

整除分块

前言

因为最近在学习莫比乌斯反演,发现整除分块这个东西几乎是非常必要的,因为是真的好用,可以把一些需要\(O(n)\)的枚举优化到$O(\sqrt n)

正文

什么式子可以用整除分块呢?一般是这样
\[\sum_{i=1}^n\lfloor\frac{n}{i}\rfloor\]
我们发现(打表或者是自己yy),对于一段连续的区间,\(\lfloor\frac{n}{i}\rfloor\)的值是不变的,那么对于这一段区间,我们就可以跳过,\(O(1)\)计算出这一段区间的值

既然是分块,那么一块的边界是什么呢?
首先,明确一点,首端点l是枚举出来的,而末端点是\(n/(n/l)\)(感性理解一下)
而据dalao分析,时间复杂度是\(O(\sqrt n)\),有了这个范围,我们就可以分块了

Code

inline void init (int ans=0) {
    for(int l=1,r,len;l<=n;l=r+1) {
        r=n/(n/l),len=r-l+1;
        ans+=len*(n/l);
    }
}

应用

很多时候,整除分块是配合其他一些函数来用的,such as \(\mu\),\(\phi\)...
当我们的区间跳跃的时候,函数值也会跳跃,所以就要记得乘上这一段区间的函数值,这个时候就需要前缀和优化了
听dalao说,有些恶心的题目会卡线性筛(T飞),这个时候就需要杜教筛,你问我杜教筛是什么?问得好,我也不知道(逃~是真的,以后有时间再补吧)

例题

放几道整除分块的例题
[AHOI2005]约数研究
[CQOI2007]余数求和
洛谷P3935 Calculating
第一题没什么思路,直接预处理,在这里放一下代码

Code

#include<bits/stdc++.h>
#define il inline
#define rg register
#define lol long long
#define Min(a,b) (a)<(b)?(a):(b)
#define Max(a,b) (a)?(b)?(a):(b)

using namespace std;

void in(int &ans) {
    ans=0; char i=getchar();
    while(i<'0' || i>'9') i=getchar();
    while(i>='0' && i<='9') ans=(ans<<1)+(ans<<3)+i-'0',i=getchar();
}

int main()
{
    int n,ans=0; in(n);
    for(rg int l=1,r,len;l<=n;l=r+1) {
        r=n/(n/l),len=r-l+1;
        ans+=n/l*len;
    }
    printf("%d\n",ans);
}

第二题也是转换一下题目要求的东西
\[a\mod b= a-\lfloor\frac{a}{b}\rfloor\times b\]
然后套一下等比数列求和就可以了
注意一下边界

Code

// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define il inline
#define rg register
#define lol long long
#define Min(a,b) (a)<(b)?(a):(b)
#define Max(a,b) (a)?(b)?(a):(b)

using namespace std;

void in(lol &ans) {
    ans=0; char i=getchar();
    while(i<'0' || i>'9') i=getchar();
    while(i>='0' && i<='9') ans=(ans<<1)+(ans<<3)+i-'0',i=getchar();
}

int main()
{
    lol n,m;in(n),in(m); lol ans=n*m;
    for(rg lol l=1,r,len;l<=n;l=r+1) {
        if(m/l!=0) r=Min(m/(m/l),n);
        else r=n; len=(r-l+1);
        ans-=(m/l)*len*(l+r)/2;
    }
    printf("%lld\n",ans);
}

第三题题解

下面是配合莫比乌斯反演的题
[POI2007]ZAP-Queries 题解1
[SDOI2015]约数个数和 题解2
YY的GCD 题解3

博主蒟蒻,随意转载.但必须附上原文链接
http://www.cnblogs.com/real-l/

转载于:https://www.cnblogs.com/real-l/p/9630810.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值