数论-整除分块

数论-整除分块

这个蒟蒻太蒻了,希望这篇文章能成为自己恶补数论的开始。

参考资料

https://blog.csdn.net/beautiful_CXW/article/details/83143756


跳转按钮

讲解证明 \color{#8af}\texttt{讲解证明} 讲解证明


代码实现 \color{#8af}\texttt{代码实现} 代码实现


经典例题 \color{#8af}\texttt{经典例题} 经典例题


讲解证明 \color{#000}\texttt{讲解证明} 讲解证明

整除分块就是用来求像

∑ i = 1 n ⌊ n i ⌋ \sum\limits_{i=1}^n\lfloor \frac{n}{i}\rfloor i=1nin

这样的式子的。

很明显,直接求要 Θ ( n ) \Theta(n) Θ(n),但是整除分块只需要 Θ ( n ) \Theta(\sqrt n) Θ(n )

整除分块的第一步是发现不同的 ⌊ n i ⌋ \lfloor \frac{n}{i}\rfloor in 的数量

如果 i ≤ n i\le\sqrt n in

很明显,因为 i i i 最多 n \sqrt n n 种,所以 ⌊ n i ⌋ \lfloor \frac{n}{i}\rfloor in 最多 n \sqrt n n 种。

如果 i > n i>\sqrt n i>n

因为 n i < n \frac{n}{i}<\sqrt n in<n ,所以 ⌊ n i ⌋ \lfloor \frac{n}{i}\rfloor in 也不到 n \sqrt n n 种。

总结:不同的 ⌊ n i ⌋ \lfloor \frac{n}{i}\rfloor in 不到 2 n 2\sqrt n 2n 种。

第二步是计算答案。因为 f ( i ) = ⌊ n i ⌋ f(i)=\lfloor \frac{n}{i}\rfloor f(i)=in 的单调性,所以 ⌊ n i ⌋ \lfloor \frac{n}{i}\rfloor in 相同的 i i i 是相邻的

显而易见的结论:对于 ⌊ n i ⌋ = d \lfloor \frac{n}{i}\rfloor=d in=d i ∈ ( ⌊ n d + 1 ⌋ , ⌊ n d ⌋ ] i\in(\lfloor\frac{n}{d+1}\rfloor,\lfloor\frac{n}{d}\rfloor] i(d+1n,dn]

比如 n = 100 , d = 6 n=100,d=6 n=100,d=6。所以 i ∈ ( 14 , 16 ] i\in(14,16] i(14,16]

所以可以以 l = ⌊ n d + 1 ⌋ + 1 , r = ⌊ n d ⌋ l=\lfloor\frac{n}{d+1}\rfloor+1,r=\lfloor\frac{n}{d}\rfloor l=d+1n+1,r=dn 为循环变量,

l = 上一次的 r + 1 , r = ⌊ n ⌊ n l ⌋ ⌋ l=\texttt{上一次的}r+1,r=\lfloor\frac{n}{\lfloor\frac{n}{l}\rfloor}\rfloor l=上一次的r+1,r=lnn


代码实现 \color{#000}\texttt{代码实现} 代码实现

讲解证明一定要仔细看,要不然代码是看不懂的。特短。必须要全局开 long   long \texttt{long long} long long,这代码可是要过 n = 1 0 12 n=10^{12} n=1012 的数据的!

code

#include <bits/stdc++.h>
using namespace std;

//&Start
#define lng long long
#define lit long double
const int inf=0x3f3f3f3f;
const lng Inf=1e17;

//&Main
lng n,ans;
int main(){
	scanf("%lld",&n);
	for(lng l=1,r;l<=n;l=r+1)
		r=n/(n/l),ans+=(r-l+1)*(n/l);
	printf("%lld\n",ans);
	return 0;
}

经典例题 \color{#000}\texttt{经典例题} 经典例题

[CQOI2007]余数求和
G ( n , k ) = ∑ i = 1 n k   m o d   i G(n,k)=\sum\limits_{i=1}^nk\bmod i G(n,k)=i=1nkmodi
数据范围: 1 ≤ n , k ≤ 1 0 9 1\le n,k\le 10^9 1n,k109


推一下(这总得看得懂吧):

∑ i = 1 n k   m o d   i = n k − ∑ i = 1 n i × ⌊ k i ⌋ \sum\limits_{i=1}^nk\bmod i=nk-\sum\limits_{i=1}^n i\times\lfloor\frac{k}{i}\rfloor i=1nkmodi=nki=1ni×ik

∑ i = 1 n i × ⌊ k i ⌋ = ∑ l , r n ⌊ k l ⌋ × ( l + r ) ( r − l + 1 ) 2 \sum\limits_{i=1}^n i\times\lfloor\frac{k}{i}\rfloor=\sum\limits_{l,r}^n\lfloor\frac{k}{l}\rfloor\times\frac{(l+r)(r-l+1)}{2} i=1ni×ik=l,rnlk×2(l+r)(rl+1)

(首项加末项乘项数除以 2 2 2)。


注意了,有可能 k < n k<n k<n。所以

r = { min ⁡ ( ⌊ k ⌊ k l ⌋ ⌋ , n )    ( ⌊ k l ⌋ > 0 ) n                         ( ⌊ k l ⌋ = 0 ) r= \begin{cases} \min(\lfloor\frac{k}{\lfloor\frac{k}{l}\rfloor}\rfloor,n)~~(\lfloor\frac{k}{l}\rfloor>0)\\ n~~~~~~~~~~~~~~~~~~~~~~~(\lfloor\frac{k}{l}\rfloor=0) \end{cases} r={min(lkk,n)  (lk>0)n                       (lk=0)


code

#include <bits/stdc++.h>
using namespace std;

//&Start
#define lng long long
#define lit long double
const int inf=0x3f3f3f3f;
const lng Inf=1e17;

//&Main
lng n,k,ans;
int main(){
	scanf("%lld%lld",&n,&k),ans=n*k;
	for(lng l=1,r;l<=n;l=r+1)
		r=(k/l)?min(k/(k/l),n):n,ans-=(l+r)*(r-l+1)/2*(k/l);
	printf("%lld\n",ans);
	return 0;
}

我还是太蒻了 QQ图片20200302204356.png祝大家学习愉快!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值