数论分块&&P2261 [CQOI2007]余数求和

本文介绍了数论分块这一数学技巧,并详细解释了如何使用它来解决正整数n和k的求和问题。通过引理证明和算法分析,展示了如何在O(n)的时间复杂度内解决此类问题。此外,还扩展讨论了二维数论分块在解决更复杂求和问题中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Label

数论分块

Description

给定正整数n,k(n,k≤109)n,k(n,k\le10^9)n,k(n,k109),求∑i=1nk\sum_{i=1}^{n}ki=1nk modmodmod iii

Solution

前置引理:

引理1:∀a,b,c∈Z,⌊abc⌋=⌊⌊ab⌋c⌋\forall a,b,c\in \Z,\lfloor\frac{a}{bc}\rfloor=\lfloor\frac{\lfloor\frac{a}{b}\rfloor}{c}\rfloora,b,cZ,bca=cba

(此处没用到,以后推式子会用)

引理2:∀n∈N+,∣{⌊nd⌋∣d∈N+,d≤n}∣≤2n\forall n\in\N^{+},|\{\lfloor\frac{n}{d}\rfloor|d\in \N^+,d\le n\}| \le2\sqrt nnN+,{dndN+,dn}2n

证明:对于d≤⌊n⌋,⌊nd⌋d\le\lfloor\sqrt n\rfloor,\lfloor\frac{n}{d}\rfloordn,dn至多有n\sqrt nn种取值;而对于d>nd>\sqrt nd>n,此时有⌊nd⌋≤n\lfloor\frac{n}{d}\rfloor\leq\sqrt ndnn,最多也只有n\sqrt nn种取值,证毕。

数论分块

数论分块一般用来解决含有⌊ni⌋\lfloor\frac{n}{i}\rfloorin的求和式子。对于任意一个iii,我们需要O(1)O(1)O(1)求出最大的jjj使得⌊ni⌋=⌊nj⌋\lfloor\frac{n}{i}\rfloor=\lfloor\frac{n}{j}\rfloorin=jn

Problem:求∑i=1n⌊ni⌋\sum_{i=1}^{n}\lfloor\frac{n}{i}\rfloori=1nin

引理333:设⌊ni⌋=k\lfloor\frac{n}{i}\rfloor=kin=k,则max{j∣⌊nj⌋=k}=⌊n⌊ni⌋⌋max\{j|\lfloor\frac{n}{j}\rfloor=k\}=\lfloor\frac{n}{\lfloor\frac{n}{i}\rfloor}\rfloormax{jjn=k}=inn

证明:⌊ni⌋=k↔k≤ni<k+1↔nk+1<i≤nk\lfloor\frac{n}{i}\rfloor=k\leftrightarrow k\leq\frac{n}{i}<k+1\leftrightarrow \frac{n}{k+1}<i\leq\frac{n}{k}in=kkin<k+1k+1n<ikn

又由于iii为正整数,故i≤nk↔i≤⌊nk⌋=⌊n⌊ni⌋⌋i\leq \frac{n}{k}\leftrightarrow i\leq\lfloor\frac{n}{k}\rfloor=\lfloor\frac{n}{\lfloor\frac{n}{i}\rfloor}\rflooriknikn=inn,所以iii的取值上界为⌊n⌊ni⌋⌋\lfloor\frac{n}{\lfloor\frac{n}{i}\rfloor}\rfloorinn

利用引理2、3,我们可以O(n)O(\sqrt n)O(n)[1,n][1,n][1,n]分成大约2n2\sqrt n2n块,每一块O(1)O(1)O(1)求和即可。

对于此题

∑i=1nk\sum_{i=1}^{n}ki=1nk modmodmod iii=∑i=1n(k−i⌊ki⌋)=nk−∑i=1ni⌊ki⌋=\sum_{i=1}^{n}(k-i\lfloor\frac{k}{i}\rfloor)=nk-\sum_{i=1}^{n}i\lfloor\frac{k}{i}\rfloor=i=1n(kiik)=nki=1niik

对于∑i=1ni⌊ki⌋\sum_{i=1}^{n}i\lfloor\frac{k}{i}\rfloori=1niik,由于分块后每块对应区间内⌊ki⌋\lfloor\frac{k}{i}\rfloorik值不变,故等差数列求和后乘以⌊ki⌋\lfloor\frac{k}{i}\rfloorik便是此分块对答案的贡献。

算法时间复杂度O(n)O(\sqrt n)O(n)

拓展:二维数论分块

∑i=1min(m,n)⌊mi⌋⌊ni⌋\sum_{i=1}^{min(m,n)}\lfloor\frac{m}{i}\rfloor\lfloor\frac{n}{i}\rfloori=1min(m,n)imin

此时将代码中 r = n/(n/i)替换成 r = min(n/(n/i), m/(m/i))即可(此时划分的块区间内⌊mi⌋,⌊ni⌋\lfloor\frac{m}{i}\rfloor,\lfloor\frac{n}{i}\rfloorim,in值显然不变,最多分成4n4\sqrt n4n块)。

Code

#include<cstdio>
#include<iostream>
#define ri register int
#define ll long long
using namespace std;

ll n,k,l,r,ans;

int main()
{
	std::ios::sync_with_stdio(false);
	cin>>n>>k;
	l=1,ans=n*k;
	while(l<=n)
	{
		if(k/l==0) break;
		r=k/(k/l);
		if(r>n) r=n;
		ans-=(k/l)*(r*(r+1)/2-l*(l-1)/2);
		l=r+1;//分块时块的划分的移动
	}
	cout<<ans;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值