【数论】数论分块(详细,小白):余数求和&&约数研究

数论分块

标题数论分块是一种非常重要的思想。就是对于一些表达式,它的值只有sqrt(n)种,那么我们就对于这sqrt(n)种数值进行分块,然后暴力算即可。

简单来说就是:

把一个数列分成一块一块的区域进行计算

下面我们来详细分析一些题目和温故一些知识点:

“ ⌊ ⌋” ←这个符号表示向下取整(⌊x⌋:表示小于 x 的最大整数;⌈x⌉:表示大于 x 的最小整数。)

mod的等价公式:

k mod i = k − ⌊ k / i ⌋× i

引入一个经典题目:

求∑Ni=1 ⌊N/i⌋ ,N≤1012

我们发现如下性质:

  1. 首先我们要了解⌊N/i⌋最多只有2√N种取值

证明:对于 i≤√N , 只有 √N 种,对于 i>√N, Ni<√N,也只有 √N 种取值,共计 √N

数列呈现出来大概是这样的:abccdddeeeeeee

  1. 枚举左端点和右端点。设左端点为i ,右端点为 i′=
    假设
    ⌊N/i′⌋ 与 ⌊N/i⌋ 相等,则 i′ 的最大值为 ⌊N/⌊N/i⌋ ⌋
    证明:
    这样一来思路就比较明显了
    两个指针 ipi的初始值是1,每次令p=
    把(p-i+1)* ⌊N/i⌋ 累加,控制更新 i = p + 1 就是答案(O(√N))

模板:

for(int i=1,p;i<=n;i=j+1){
        p=n/(n/i);
        ans+=(n/i)*(p-i+1);
    }

那么我们来看几道题熟悉一下:

P2261 [CQOI2007]余数求和

题目描述:

给出正整数 n 和 k 计算 G(n, k)=k mod 1 + k mod 2 + k mod 3 + …+k mod n的值 其中 k mod i表示 k 除以 i 的余数。

例如 G(10, 5)=5 mod 1 + 5 mod 2 + 5 mod3 + 5 mod 4 + 5 mod 5 … + 5 mod10=0+1+2+1+0+5+5+5+5+5=29

Input

两个整数 n ,k

Output

答案

Sample Input

10 5

Sample Output

29

分析:

由题意得:

k mod i = k − ⌊ k / i ⌋× i 得:


样例打表如下:

因为有连续的⌊N/i⌋的值是一样的,所以我们可以用除法分块来解决问题。

在这里插入图片描述
我们设

t=⌊k/i⌋,

需要注意的是,当t 等于0时候,右边界p一定在n位置上(正数求余结果>=0)。即:

if(t==0)p=n

当t不等于0时候,为了防止他右边界越界,我们将右边界p加上一个min函数防止其大于n。

if(t!=0)p=min(n,⌊k/⌊k/i⌋⌋)

每一块的和 = 当前块的 × 当前块元素个数 × 当前块 i 的平均值

t×(p-i+1)×(p+i) /2

最后结果用n×k-⌊k/i⌋×(p-i+1)×(p+i) /2即为答案。

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<math.h>
#include<cmath>
using namespace std;
typedef long long ll;
ll sum=0, n,k;
int main()
{
	cin>>n>>k;
	sum=n*k;
	int p;
	for(ll i=1,t;i<=n;i=p+1)//i,p就是一块里面的左右边界
	{
		t=k/i;//求出当前的t 
        if (t==0) p=n;
        else p=min(k/t,n);
        //p=(k/i?min(k/(k/i),n):n);
		sum-=(k/i)*(i+p)*(p-i+1)/2;
		
	}
	cout<<sum;
}

我们再看一道简单裸题:

P1403 [AHOI2005]约数研究

在这里插入图片描述
根据表格
1-n的因子个数,可以看成共含有2因子的数的个数+含有3因子的数的个数……+含有n因子的数的个数,在1~n中含有“2”这个因子的数有n/2个,3有n/3个,以此类推
得到公式:

f(i)=⌊n/i⌋

套用模板求解即可(代码就不粘贴了)
.
.
.
.
.
······
ps:
参考洛谷题解和博主:https://www.cnblogs.com/five20/p/9199192.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值