整除分块笔记

UVA11526 H(n)

大概题意:有T组数据,对于每组给出一个整数 n 。对于每组数据求出 i=1nni


Solution

你看它函数都给出来了,直接抄不好吗
TLE狂喜

众所周知,这题要用分块
正如标题,这题可以看作分块模板

何为分块?

以此题为例,当 n=15 时,
sum=15+7+5+3+3+2+2+1+1+1+1+1+1+1+1
可以看出 3,2,1重复出现
而题目给的解法会重复计算这些重复出现的数字
所以这是我们要利用分块的思想来减少计算量
比如此题中 2 出现了2次,那我们怎么确定 2 第一次和最后一次出现的位置呢?


还是以15为例
我们从 151 开始计算
此时我们已经确定了结果为 15左界,所以我们要寻找右界
观察 ni,可以发现 :
当结果为 x 时一定满足 nx×i
所以我们可以求得最后一个结果为 x 的数肯定为 n/x
但是我们也不能枚举x,因为这样也是 O(n)肯定会寄
但是我们已经求出了上一个值的的右界
众所周知,左界 +1就是右界
所以 x 的另一种求法就是 n/


代码

1#define ll long long  //偷懒小技巧
2inline ll f(ll n){  //inline 可以更快
3	ll sum=0;
4	for(ll l=1,r;l<=n;l=r+1){  //左界
5        //开long long避免炸精度
6		r = n / (n / l);  //右界
7		sum += (r - l + 1) * (n / l);
8	}
9	return sum;
10}

代码还是自己写有效果,抄一遍也比复制好


双倍经验1

P2261 [CQOI2007]余数求和
温馨提示:这题和上一题几乎一样,就是多了一些细节上的处理。
参考代码:

点我点我
#include<bits/stdc++.h>
using namespace std;
int main(){
	long long n, k;
	cin>>n>>k;
	long long cnt=n*k;
	for(long long l=1, r; l<=n; l=r+1){
		if (k/l!=0) r=min((k/(k/l)), n);
		else r=n;
		cnt-=(r+l)*(k/l)*(r-l+1)/2;
	}
	cout<<cnt;
}

学习整除时,写了一道题,写完后打开题解突然发现第一篇和上文代码一样。

[AHOI2005]约数研究

经过仔细的思考,我发现了其中的联系。 真相只有一个
x (1xn) 中约数中包含约数 i (1in) 的数有ni
你品,你细品


双倍经验2

P2424 约数和
温馨提示:这题也只是多了一些细节。

实在想不出再来点我欧~
#include<bits/stdc++.h>
using namespace std;
#define ll long long

ll f(ll n){
	if(n<=1) return n;
	ll res=0;
	for(ll l=1,r;l<=n;l=r+1){
		r = n / (n / l);
		res += (r - l + 1) * (n / l) * (l + r) / 2;
	}
	return res;
}

int main(){
    ll x,y;
    scanf("%lld%lld", &x, &y);
    printf("%lld\n", f(y)-f(x-1));
}

Update

2022.9.24:增加 P2424 约数和[AHOI2005]约数研究

posted @   niuerdao  阅读(22)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示