数论分块总结

数论分块总结:

数论分块类似于倍增的思想,可以在某些问题种,将o(n)的时间复杂优化。

(1)首先先来看最简单的分块:

即求
∑ i = 1 n ⌊ n i ⌋ \sum_{i=1}^n{\lfloor \frac{n}{i} \rfloor} i=1nin

如果没有学数论分块的话,肯定就是暴力枚举了。通过观察我们可以发现:

在这里插入图片描述

对于 [n/i] 下取整,某一段连续的值是一样的,显然对于这一段我们可以不用一个一个的算,如果确定了那段的左右边界以及值的话,我们可以通过 (r-l+1) *val 直接算出这一段的和。

怎么确定左右边界和值呢?我们可以以右边界为分割线,化成若干段就行了,然后枚举左边界一段一段的求。

因为对于某一段val值是相同的,假设如果我们知道了 值val,那么右边界就很容易求了,右边界就是最远的嘛,n除以val 的最大值,也就是 [n/val] 下取整。对于val,因为这一段任意一个i, [n/i] 下取整都是相同的,很显然可以用左边界求。代码如下:

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

(2)对于多关键字数论分块
∑ i m i n ( N , M ) ⌊ N i ⌋ ⌊ M i ⌋ \sum_i^{min(N,M)}{\lfloor\frac{N}{i}\rfloor\lfloor\frac{M}{i}\rfloor} imin(N,M)iNiM
本质思想和普通的数论分块是一样的,即找出相等部分的左右边界,对于双关键字的显然相等部分就是两块相等部分的交集,推广到任意关键字同理。

所以代码如下:

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

(3)对于
∑ i n ⌊ N i ⌋ = ∑ i n ⌊ N i ⌋ ∗ f ( i ) \sum_i^n\lfloor \frac{N}{i} \rfloor = \sum_i^n{\lfloor\frac{N}{i}\rfloor*f(i)} iniN=iniNf(i)
显然,如果f[i]=1,就是上面的形式。

对于任意的f(x), 其思想本质还是找相同的部分。假设对于某连续的一段 [n/i] 下取整的值为 val ,那么这一段就是

val* f[l] + val * f[2] + … +val *f [r].显然可以将val 提出来,

即 val * (f[l] + …+ f[r]) 。 一但预处理出f(x)的前缀和,则可表示为 val * ( sum[r] - sum[l-1] )。

代码如下:

//预处理前缀和
for(int l=1;l<=n;l=r+1)
{
    r=n/(n/l);
    ans+=(n/l)*(sum[r]-sum[l-1]);
}

另外还有数论分块的一些性质
通过打表归纳总结:
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值