[数论数学]反演卷积的应用-快速求和化简

本文介绍了数论分块和反演卷积在求和问题中的应用,包括整除分块、gcd快速求和以及快速求和举例。通过具体的例子,如整除分块求和优化、一维和二维gcd求和、以及快速求和算法,展示了如何将复杂求和问题简化并快速求解。文章涵盖了欧拉函数、整除分块、莫比乌斯反演和杜教筛等数论概念和技术,提供了处理大规模数据的高效方法。
摘要由CSDN通过智能技术生成

可以说是卷积和反演的综合应用

一、整除分块(数论分块)

补充一点基础知识…

具体来说就是:如果我们要求 ∑ i = 1 n ⌊ n i ⌋ \sum \limits_{i=1}^n\lfloor\frac{n}{i}\rfloor i=1nin,并不需要用朴素算法 O ( n ) O(n) O(n)去求,可以加快速度。

定理1:所有 1 ≤ i ≤ n 1 \leq i \leq n 1in ⌊ n i ⌋ \lfloor\frac{n}{i}\rfloor in的结果最多只有 2 n 2\sqrt n 2n 种。

证明:对于 i ∈ [ 1 , n ] i \in [1,\sqrt n] i[1,n ],显然最多只有 n \sqrt n n 种取值,而对于 i ∈ [ n + 1 , n ] i \in [\sqrt n+1,n] i[n +1,n] ⌊ n i ⌋ ≤ n \lfloor\frac{n}{i}\rfloor\leq\sqrt n inn ,因此也最多有 n \sqrt n n 种取值,两个部分相加,因此最多有 2 n 2\sqrt n 2n 种取值。

定理2:对于确定的 i i i,能使得 ⌊ n x ⌋ = ⌊ n i ⌋ \lfloor\frac{n}{x}\rfloor=\lfloor\frac{n}{i}\rfloor xn=in x m a x = ⌊ n ⌊ n i ⌋ ⌋ x_{max}=\Big\lfloor\cfrac{n}{\lfloor\frac{n}{i}\rfloor}\Big\rfloor xmax=inn

这里选取了两种证明方法。

证法1:记 f ( i ) = ⌊ n ⌊ n i ⌋ ⌋ f(i)=\Big\lfloor\cfrac{n}{\lfloor\frac{n}{i}\rfloor}\Big\rfloor f(i)=inn,则因为 ⌊ n i ⌋ \lfloor \frac{n}{i} \rfloor in单调不减,而且 f ( i ) ≥ i f(i) \ge i f(i)i,所以必有 ⌊ n f ( i ) ⌋ ≤ ⌊ n i ⌋ \lfloor\frac{n}{f(i)}\rfloor \leq \lfloor \frac{n}{i} \rfloor f(i)nin,又因为 f ( i ) ≤ n ⌊ n i ⌋ f(i)\leq\cfrac{n}{\lfloor\frac{n}{i}\rfloor} f(i)inn,所以有:

⌊ n f ( i ) ⌋ ≥ n / ( n ⌊ n i ⌋ ) = ⌊ n i ⌋ \lfloor\frac{n}{f(i)}\rfloor \ge n/(\frac{n}{\lfloor\frac{n}{i}\rfloor})=\lfloor\frac{n}{i}\rfloor f(i)nn/(inn)=in

同时证明大于等于和小于等于,因此 ⌊ n f ( i ) ⌋ = ⌊ n i ⌋ \lfloor\frac{n}{f(i)}\rfloor=\lfloor\frac{n}{i}\rfloor f(i)n=in

另外,若 f ( i ) f(i) f(i)不是满足条件的最大值,则 ⌊ n f ( i ) + 1 ⌋ = ⌊ n i ⌋ \lfloor\frac{n}{f(i)+1}\rfloor=\lfloor\frac{n}{i}\rfloor f(i)+1n=in,则 f ( i ) = f ( f ( i ) + 1 ) f(i)=f(f(i)+1) f(i)=f(f(i)+1),而又 f ( i ) ≥ i f(i)\ge i f(i)i,矛盾,因此 f ( i ) f(i) f(i)就是满足要求的最大值。


证法2:记 n = d i + p = d x + q ( 0 ≤ p , q &lt; n ) n=di+p=dx+q\quad(0\leq p,q&lt;n) n=di+p=dx+q(0p,q<n),则 ⌊ n x ⌋ = ⌊ n i ⌋ = d \lfloor\frac{n}{x}\rfloor=\lfloor\frac{n}{i}\rfloor=d xn=in=d,由前式两等式相减得:

q = p − d ( x − i ) q = p − d k ( k = x − i ) q=p-d(x-i)\qquad\qquad q=p-dk\quad(k=x-i) q=pd(xi)q=pdk(k=xi)

要使 x x x最大,也就是要让 k k k尽量大,由 q ≥ 0 q\ge 0 q0可得 k k k的最大值为 k m a x = ⌊ p d ⌋ k_{max}=\lfloor\frac{p}{d}\rfloor kmax=dp

此时有: x = i + d m a x = i + ⌊ p d ⌋ x=i+d_{max}=i+\lfloor\frac{p}{d}\rfloor x=i+dmax=i+dp,将 p , d p,d p,d代换得: x = i + ⌊ n   m o d   i ⌊ n i ⌋ ⌋ x=i+\Big\lfloor\frac{n\ mod\ i}{\lfloor\frac{n}{i}\rfloor}\Big\rfloor x=i+inn mod i,将 n   m o d   i n\ mod\ i n mod i代换,并将 i i i乘上去可得:

x = i + ⌊ n − i ⌊ n i ⌋ ⌊ n i ⌋ ⌋ = ⌊ i ⌊ n i ⌋ + n − i ⌊ n i ⌋ ⌊ n i ⌋ ⌋ = ⌊ n ⌊ n i ⌋ ⌋ x=i+\Big\lfloor\frac{n-i\lfloor\frac{n}{i}\rfloor}{\lfloor\frac{n}{i}\rfloor}\Big\rfloor=\Big\lfloor\frac{i\lfloor\frac{n}{i}\rfloor+n-i\lfloor\frac{n}{i}\rfloor}{\lfloor\frac{n}{i}\rfloor}\Big\rfloor=\Big\lfloor\cfrac{n}{\lfloor\frac{n}{i}\rfloor}\Big\rfloor x=i+inniin=iniin+niin=inn

同样得到了结论。


因此我们只要通过上面对商的讨论,就可以在 O ( n ) O(\sqrt n) O(n )时间复杂度内快速计算 ∑ i = 1 n ⌊ n i ⌋ \sum \limits_{i=1}^n\lfloor\frac{n}{i}\rfloor i=1nin

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

来看一道题目。

题目大意:给定 n , k ≤ 1 0 9 n,k \leq 10^9 n,k109,求出 ∑ i = 1 n k   m o d   i = k   m o d   1 + . . . + k   m o d   n \sum \limits_{i=1}^nk\ mod\ i=k\ mod\ 1+...+k\ mod\ n i=1nk mod i=k mod 1+...+k mod n洛谷2261

分析:直接 O ( n ) O(n) O(n)做是肯定不行的,这时我们想到利用余数的定义: n   m o d   i = n − i ⌊ n i ⌋ n\ mod\ i=n-i\lfloor\frac{n}{i}\rfloor n mod i=niin,于是我们就可以开心化简了:

∑ i = 1 n k   m o d   i = k n − ∑ i = 1 n i ⌊ k i ⌋ \sum \limits_{i=1}^n k\ mod\ i=kn-\sum\limits_{i=1}^n i\lfloor\frac{k}{i}\rfloor i=1nk mod i=kni=1niik

而这个式子的后面一部分非常像整除分块的形式,但是还不完全一样。不过这也不难,我们只要将上面的代码中原本表示 l − r l-r lr之间数的个数的 ( r − l + 1 ) (r-l+1) (rl+1)替换成 l − r l-r lr的和 ( l + r ) ( r − l + 1 ) 2 \frac{(l+r)(r-l+1)}{2} 2(l+r)(rl+1)即可。

有一点需要注意,此时求和上限和被除数不同,需要加上一句额外判断,当 ⌊ k ⌊ k i ⌋ ⌋ \Big\lfloor\cfrac{k}{\lfloor\frac{k}{i}\rfloor}\Big\rfloor ikk超过了 n n n时也只能取到 n n n

#include <bits/stdc++.h>
using namespace std;
long long ans,n,k;
int main () {
   
	scanf("%lld%lld",&n,&k);
	ans=n*k;
	for (long long l=1,r;l<=min(n,k);l=r+1) {
   
		r=min(k/(k/l),n);
		ans-=(k/l)*(l+r)*(r-l+1)/2;
	}
	printf("%lld\n",ans);
	return 0;
}

通过上面这道题目我们能看出来什么?其实整除分块并不只能求原本的标准形式。事实上,形如整除式后面乘上一个函数的值这样的求和式,都可以用整除分块的方法做出,即:

∑ i = 1 n   ⌊ n i ⌋   f ( i ) = ∑   ⌊ n l ⌋   ( s ( r ) − s ( l − 1 ) ) \sum \limits_{i=1}^n\ \lfloor\frac{n}{i}\rfloor\ f(i)=\sum \ \lfloor\frac{n}{l}\rfloor\ (s(r)-s(l-1)) i=1n in f(i)= ln (s(r)s(l1))

其中 s ( k ) = ∑ i = 1 k f ( i ) s(k)=\sum \limits_{i=1}^kf(i) s(k)=i=1kf(i),即函数的前缀和, l , r l,r l,r与上面代码中的意义相同。其实上面的例子也是这样,只是 s ( i ) s(i) s(i)恰好是一个等差数列的形式,很容易算出。


二、gcd快速求和

由于这个部分比较好玩,而且与反演和卷积也有点关系,体现一些基本思想,就先讲一些了。

一维gcd求和:求 ∑ i = 1 N g c d ( N , i ) \sum\limits_{i=1}^Ngcd(N,i) i=1Ngcd(N,i)洛谷2303

分析:我们对不同的数据范围进行逐层递进的分析:

(1) N ≤ 1 0 5 N \leq 10^5 N105

这个非常简单,只要你会欧几里得算法,就可以直接计算 g c d ( N , i ) gcd(N,i) gcd(N,i)的值,然后将所有结果相加,暴力计算即可得到答案,时间复杂度 O ( N log ⁡ N ) O(N\log N) O(NlogN)

(2) N ≤ 1 0 9 N \leq 10^9 N109

主要的思维都体现在这里了…首先处理这种最大公因数问题的最常用方法之一,是枚举最大公因数的值 d d d,也就是我们枚举每一个可能的 d d d,然后去计数有多少个为 d d d的结果,将 d d d与计数量相乘即可得到结果为 d d d的最大公因数和了,而 d = g c d ( N , i ) d=gcd(N,i) d=gcd(N,i),则显然 d ∣ N d|N dN,因此可以这样枚举:

∑ d ∣ N   d   ∑ i = 1 N [ g c d ( N , i ) = d ] \sum \limits_{d|N}\ d\ \sum\limits_{i=1}^N[gcd(N,i)=d] dN d i=1N[gcd(N,i)=d]

这是第一步技巧,将gcd提取出来放在外面。

接下来还要继续化简,我们现在感觉这个方括号里的等式真的没什么用,那么遇到这种情况有两种方法,一种是用后面要讲的莫比乌斯反演,但这里还不必要;另一种就是“约分”,也就是将内侧求和的每一个d都约去,这样的话 N N N就变成了 N d \frac{N}{d} dN了:

∑ d ∣ N   d   ∑ i = 1 N d [ g c d ( N d , i ) = 1 ] \sum \limits_{d|N}\ d\ \sum\limits_{i=1}^\frac{N}{d}[gcd(\frac{N}{d},i)=1] dN d i=1dN[gcd(dN,i)=1]

这时候你就应该意识到了:此时里面这个求和号其实就是欧拉函数!我们将它表示一下:

∑ d ∣ N   d   φ ( N d ) \sum \limits_{d|N}\ d\ \varphi(\frac{N}{d}) dN d φ(dN)

这样做 1 0 9 10^9 109数据就足够了,我们枚举N的因子d,并算出N/d的欧拉函数值就可以了。

(3) N ≤ 1 0 12 N \leq 10^{12} N1012

这时上面计算欧拉函数的时间代价就太高了,因此需要再次优化。

如果你掌握之前讲的卷积足够好的话,你就应该及时意识到,上面的这个式子是一个卷积式,其实是 i d id id φ \varphi φ的卷积。之前我们还学过:两个积性函数的卷积依然是积性函数,所以此时我们假设 f ( N ) = ∑ d ∣ N   d   φ ( N d ) f(N)=\sum \limits_{d|N}\ d\ \varphi(\frac{N}{d}) f(N)=dN d φ(dN),此时 f f f就是一个积性函数。那么我们将 n n n分解素因数为 N = p 1 c 1 . . . p n c n N=p_1^{c_1}...p_n^{c_n} N=p1c1...pncn,则:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值