【学习笔记】特殊数论函数求和

220 篇文章 2 订阅
12 篇文章 0 订阅

前言

已经不知道第几次修改了。修过很多锅,也陆续新增了少许内容。数学的魅力就在于,它是没有被穷尽的。我也不相信它会有被穷尽的一天。

Comment. 用 P \mathbb{P} P 表示质数集,用 ■ \blacksquare 表示证毕,用 Comment 表示注释。

min25 \texttt{min25} min25 / / / 洲阁筛

min25 \texttt{min25} min25 筛或洲阁筛的主要目的是求积性函数 f ( x ) f(x) f(x) 的前缀和。——其实也可以拓展到部分非积性函数 [2]。

Comment. 其实它也不能叫做筛法吧,但是其思想确实是筛法的。

我们首先用直观的方法描述之。该算法的总体思路是:

  • 第一步,求出质数 p p p 对应的 f ( p ) f(p) f(p) 的前缀和。
  • 第二步,求出 f ( x ) f(x) f(x) 的前缀和。

为什么会这样?因为质数的幂——相较于质数而言——数量很少。

小质数

一般的积性函数是复杂的。所以我们需要用 完全积性函数拟合 原函数:只需要找到完全积性函数 ℏ ( x ) \hbar(x) (x) 使得 ℏ ( p ) = f ( p )    ( p ∈ P ) \hbar(p)=f(p)\;(p\in\mathbb{P}) (p)=f(p)(pP) 不变。因为 step one \text{step one} step one 只需要求出 ∑ p ∈ P f ( p ) \sum_{p\in\mathbb{P}}f(p) pPf(p)

Comment. 其实也可以不是完全积性的,可见后文 zzt \texttt{zzt} zzt 求和法。

g ( n , j ) g(n,j) g(n,j) 表示 [ 2 , n ] [2,n] [2,n] 去除前 j j j 个质数的倍数之后,剩余数字的 f ( x ) f(x) f(x) 之和。注意:要求 g ( n , j ) g(n,j) g(n,j) 时刻包含 [ 2 , n ] [2,n] [2,n] 之间所有质数的 f ( x ) f(x) f(x),也就是说,去除的是质数的 “真倍数”(不包含质数本身)。

形式化地,记 { p } \{p\} {p} 为从小到大的质数(角标从 1 1 1 开始),则
g ( n , j ) = ∑ i = 1 j f ( p i ) + ∑ i = 1 n [ p 1 ∤ i ∧ p 2 ∤ i ∧ ⋯ ∧ p j ∤ i ]    f ( i ) g(n,j)=\sum_{i=1}^{j}f(p_i)+\sum_{i=1}^{n}[p_1\nmid i\land p_2\nmid i\land\cdots\land p_j\nmid i]\;f(i) g(n,j)=i=1jf(pi)+i=1n[p1ip2ipji]f(i)

我们的目标是求出 g ( n , + ∞ ) g(n,+\infty) g(n,+),也就是只留下了质数。

考虑 d p \tt dp dp 求解。转移过程就是去掉 k p j    ( k > 1 ) kp_j\;(k>1) kpj(k>1) 。显然 k k k 不应该是前 ( j − 1 ) (j{\rm-}1) (j1) 个质数的倍数,因为那是已经被移除的数。又因为 f ( x ) f(x) f(x) 是完全积性函数,有 f ( k p j ) = f ( p j ) f ( k ) f(kp_j)=f(p_j)f(k) f(kpj)=f(pj)f(k),于是有转移式
g ( n , j ) = g ( n , j − 1 ) − f ( p j ) [ g ( ⌊ n p j ⌋ , j − 1 ) − sumf ⁡ ( j − 1 ) ]    ( p j ⩽ n ) g(n,j)=g(n,j{\rm-}1)-f(p_j)\left[ g\left(\left\lfloor{\scriptsize\frac{n}{p_j}}\right\rfloor,j{\rm-}1\right) -\operatorname{sumf}(j{\rm-}1) \right]\;(p_j\leqslant\sqrt{n}) g(n,j)=g(n,j1)f(pj)[g(pjn,j1)sumf(j1)](pjn )

这里 sumf ⁡ ( j − 1 ) = ∑ i = 1 j − 1 f ( p i ) \operatorname{sumf}(j{\rm-}1)=\sum_{i=1}^{j-1}f(p_i) sumf(j1)=i=1j1f(pi),因为 g g g 里面没有挖掉质数本身,减去它以修正。

特别地,如果 n < p j   2 n<p_j^{\thinspace 2} n<pj2,显然没有更多的数字需要被筛掉,此时 g ( i , j ) = g ( i , j − 1 ) g(i,j)=g(i,j{\rm-}1) g(i,j)=g(i,j1) 。若在 j j j 这一维上做滚动数组,则无需修改这些位置。同时可知,需要的质数最大是 n \sqrt n n ,所以直接线性筛即可求出 sumf ⁡ \operatorname{sumf} sumf 了。

我们要对 g ( i , 0 ) g(i,0) g(i,0) 赋初值。所以又涉及一个问题是,拟合函数的前缀和要易于求解。一般来说,我们会选择单项式作为拟合函数。不会真的有毒瘤题目需要用可以杜教筛的数论函数来拟合吧

Comment. 多项式不总是完全积性的。将其拆解为多个单项式,分别求 g g g 再相加即可。

n n n 的范围很大。注意到求解 g ( n , j ) g(n,j) g(n,j) 时,只递归到 n ′ = ⌊ n v ⌋ n'=\lfloor{n\over v}\rfloor n=vn 的值;最后我们会看到,若求解 s s s 长度的前缀和,则我们只需求出 n = ⌊ s v ⌋    ( v ∈ N + ) n=\lfloor{s\over v}\rfloor\;(v\in\N^+) n=vs(vN+) 的答案,这样的 n n n 只有 O ( s ) \mathcal O(\sqrt{s}) O(s ) 个。

具体复杂度计算见后文。

大质数

注意下面的方法中 f ( 1 ) f(1) f(1) 总是会被算漏。记得最后加上。

min25 \texttt{min25} min25

我们前面只求出了质数的求和是 g ( s , + ∞ ) g(s,+\infty) g(s,+),所以现在我们只需要考虑合数了。

好消息:合数的最小质因数是不超过 s \sqrt{s} s 的!于是咱可以枚举这玩意儿。记 x x x 的最小质因数为 γ ( x )    ( x ⩾ 2 ) \gamma(x)\;(x\geqslant 2) γ(x)(x2)

h ( n , j ) = ∑ i = 2 n [ γ ( i ) ⩾ p j ]    f ( i ) h(n,j)=\sum_{i=2}^{n}[\gamma(i)\geqslant p_j]\;f(i) h(n,j)=i=2n[γ(i)pj]f(i) 。欲求即 h ( s , 1 ) h(s,1) h(s,1)

枚举最小质因子与其幂次,可以写出转移式
h ( n , j ) = g ( n , + ∞ ) − sumf ⁡ ( j − 1 ) + ∑ i ⩾ j ∑ k = 1 ⌊ log ⁡ p i n ⌋ f ( p i   k ) [ h ( ⌊ n p i k ⌋ , i + 1 ) + [ k ≠ 1 ] ] h(n,j)=g(n,+\infty)-\operatorname{sumf}(j{-}1) \\ +\sum_{i\geqslant j} \sum_{k=1}^{\lfloor\log_{p_i}n\rfloor} f(p_i^{\thinspace k})\left[ h\Big(\Big\lfloor{ \scriptsize{n\over p_i^{\thinspace k}}} \Big\rfloor,i{\rm +}1\Big) +[k \ne 1] \right] h(n,j)=g(n,+)sumf(j1)+ijk=1logpinf(pik)[h(pikn,i+1)+[k=1]]

g ( n , + ∞ ) − sumf ⁡ ( j − 1 ) g(n,+\infty)-\operatorname{sumf}(j{-}1) g(n,+)sumf(j1) 计算了 [ 2 , n ] [2,n] [2,n] 中的质数 p c    ( c ⩾ j ) p_c\;(c\geqslant j) pc(cj),用 f ( p i   k ) ⋅ h ( …   ) f(p_i^{\thinspace k})\cdot h(\dots) f(pik)h() 计算了含至少两个质因子的合数,用 [ k ≠ 1 ]    f ( p i   k ) [k\ne 1]\;f(p_i^{\thinspace k}) [k=1]f(pik) 计算了质数的幂,不重不漏。

step one \text{step one} step one 同理,只在 p i ⩽ n p_i\leqslant\sqrt{n} pin 时转移。有趣的是,我们可以直接 递归,而且 不进行记忆化。详细复杂度计算见后文。

洲阁筛

h ( n , j ) h(n,j) h(n,j) 始终包含 [ 2 , s ] [2,s] [2,s] 全体质数。这是利于转移的要求。
h ( n , j ) = h ( n , j + 1 ) + ∑ k = 1 ⌊ log ⁡ p j n ⌋ f ( p j   k ) [ h ( ⌊ i p j k ⌋ , k + 1 ) − sumf ⁡ ( j ) + [ k ≠ 1 ] ] h(n,j)=h(n,j{+}1)+ \sum_{k=1}^{\lfloor\log_{p_j}n\rfloor} f(p_j^{\thinspace k})\left[ h\Big( \Big\lfloor{\scriptsize \frac{i}{p_j^{\thinspace k}} }\Big\rfloor, k{+}1 \Big)-\operatorname{sumf}(j)+[k\ne 1] \right] h(n,j)=h(n,j+1)+k=1logpjnf(pjk)[h(pjki,k+1)sumf(j)+[k=1]]

转移条件仍为 p j ⩽ n p_j\leqslant\sqrt{n} pjn 。初值为 h ( n , + ∞ ) = g ( n , + ∞ ) h(n,+\infty)=g(n,+\infty) h(n,+)=g(n,+),相当于在 g g g 的基础上接着递推。

没错,二者明明只是递归和递推的区别,但它的名字就变成了洲阁筛。小编也很好奇。

代码实现

嗯,直接上代码。以板题 f ( p k ) = p k ⋅ ( p k − 1 ) f(p^k)=p^k\cdot (p^k{-}1) f(pk)=pk(pk1) 为例:需要用 x 2 x^2 x2 x x x 分别拟合,于是将 g g g 设为 pair \texttt{pair} pair 类型。

这里的代码是递归的。在 补充信息 中的题目有递推版代码。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cctype>
using namespace std;
# define rep(i,a,b) for(int i=(a); i<=(b); ++i)
# define drep(i,a,b) for(int i=(a); i>=(b); --i)
typedef long long llong;
inline int readint(){
	int a = 0, c = getchar(), f = 1;
	for(; !isdigit(c); c=getchar())
		if(c == '-') f = -f;
	for(; isdigit(c); c=getchar())
		a = (a<<3)+(a<<1)+(c^48);
	return a*f;
}

const int MOD = 1e9+7, SQRTN = 100005;
int primes[SQRTN], primes_size;
bool isPrime[SQRTN];
struct Node{
	int one, two;
	Node() = default;
	Node(int x):one(x),two(int(llong(x)*x%MOD)){}
	Node(int _o,int _t):one(_o),two(_t){}
	Node operator * (const Node &t) const {
		return Node(int(llong(one)*t.one%MOD),
			int(llong(two)*t.two%MOD));
	}
	Node operator - (const Node &t) const {
		return Node((one-t.one+MOD)%MOD,(two-t.two+MOD)%MOD);
	}
	int val() const { return (two-one+MOD)%MOD; }
};
Node sumf[SQRTN];
void sieve(int n){
	memset(isPrime+2,true,n-1);
	for(int i=2; i<=n; ++i){
		if(isPrime[i]){
			primes[++ primes_size] = i;
			Node &v = sumf[primes_size] = sumf[primes_size-1];
			if((v.one += i) >= MOD) v.one -= MOD;
			v.two = int((v.two+llong(i)*i)%MOD);
		}
		for(int j=1; j<=primes_size&&primes[j]<=n/i; ++j){
			isPrime[i*primes[j]] = false;
			if(i%primes[j] == 0) break;
		}
	}
}

const int inv2 = (MOD+1)>>1, inv3 = (MOD+1)/3;
int haxi[2][SQRTN]; // value or divisor
inline int& index_(const llong &x,const llong &n){
	return (x < SQRTN) ? haxi[0][x] : haxi[1][n/x];
}
llong w[SQRTN<<1]; ///< positions to get sum
Node g[SQRTN<<1]; ///< 2 times SQRTN
void step_one(const llong &n){
	int tot = 0; ///< allocate index
	for(llong i=1; i<=n; i=n/(n/i)+1){
		w[++ tot] = n/i; index_(n/i,n) = tot;
		g[tot].one = int(((w[tot]%MOD+1)*(w[tot]%MOD)>>1)%MOD)-1;
		g[tot].two = int((w[tot]<<1|1)%MOD*(w[tot]%MOD+1)
			%MOD*(w[tot]%MOD)%MOD*inv2%MOD*inv3%MOD)-1;
	}
	for(int j=1; j<=primes_size; ++j){
		if(primes[j] > n/primes[j]) break;
		for(int i=1; i<=tot; ++i){
			if(primes[j] > w[i]/primes[j]) break;
			g[i] = g[i]-Node(primes[j])*(
				g[index_(w[i]/primes[j],n)]-sumf[j-1]);
		}
	}
}

inline llong func(const llong &x){
	return (x-1)%MOD*(x%MOD)%MOD; // definition
}
int step_two(const llong &x,int i,const llong &n){
	if(primes[i] > x) return 0;
	int res = g[index_(x,n)].val()-sumf[i-1].val();
	for(; i<=primes_size&&primes[i]<=x/primes[i]; ++i){
		llong t = primes[i], fk = x/t;
		for(; t<=fk; t*=primes[i])
			res = int((func(t*primes[i])+func(t)
				*step_two(x/t,i+1,n)+res)%MOD);
	}
	return (res >= 0) ? res : (res+MOD);
}

int main(){
	sieve(SQRTN-1); // just do it
	llong n; scanf("%lld",&n); step_one(n);
	printf("%d\n",step_two(n,1,n)+1);
	return 0;
}

时间复杂度

小质数

step one \text{step one} step one 的复杂度比较好算,因为转移是 O ( 1 ) \mathcal O(1) O(1) 的,只算转移次数。每个 w w w 要用到不超过 w \sqrt{w} w 的质数,所以复杂度约为

∑ i = 1 n n i ln ⁡ n i ≈ ∫ 1 n n x ln ⁡ ( n x ) d x \sum_{i=1}^{\sqrt{n}}\frac{\sqrt{n\over i}}{\ln\sqrt{n\over i}}\approx \int_{1}^{\sqrt{n}}{\sqrt{n}\over \sqrt{x}\ln\left({n\over x}\right)}\text dx i=1n lnin in 1n x ln(xn)n dx

2021 / 8 / 1    u p d a t e \tt 2021/8/1\;update 2021/8/1update:由于被 H a n d I n D e v i l \sf HandInDevil HandInDevil 臭骂了一顿,稍微讲讲用积分计算复杂度的事儿。它实际上是将数论函数的求和,转化为了连续函数的积分。这是否能作为渐进复杂度呢?

一般而言,原数论函数是单调的,且不存在奇点。在此情形下,考虑用 ∫ δ δ + 1 g ( x ) d x \int_{\delta}^{\delta+1} g(x)\text dx δδ+1g(x)dx 拟合 f ( δ )    ( δ ∈ Z ) f(\delta)\;(\delta\in\Z) f(δ)(δZ),则结果是偏小(或偏大)的;而用 ∫ δ − 1 δ g ( x ) d x \int_{\delta-1}^{\delta}g(x)\text dx δ1δg(x)dx 去拟合 f ( δ ) f(\delta) f(δ) 又会偏大(或偏小)。由于有 0 0 0 是奇点的风险,上界(或下界)可能是 ∫ 1 n g ( x ) d x + f ( 1 ) \int_1^ng(x)\text dx+f(1) 1ng(x)dx+f(1),下界(或上界)是 ∫ 2 n + 1 g ( x ) d x \int_2^{n+1}g(x)\text dx 2n+1g(x)dx 。二者往往是等阶的,那么就 “夹逼” 出了确界。

现在回到正题上。由于我已知道了结果,我告诉你
∫ 1 x ln ⁡ ( n x ) d x = O [ x ln ⁡ ( n x ) ] \int{1\over \sqrt{x}\ln({n\over x})}\text dx=\mathcal O\left[{\sqrt x\over\ln({n\over x})}\right] x ln(xn)1dx=O[ln(xn)x ]

因为 ln ⁡ x \ln x lnx 型函数作分母比较特殊:右式的导数实际上是 1 2 x ln ⁡ ( n x ) + 1 x ln ⁡ 2 ( n x ) \frac{1}{2\sqrt x\ln({n\over x})}+\frac{1}{\sqrt x\ln^2({n\over x})} 2x ln(xn)1+x ln2(xn)1,但是在大 O \mathcal O O 表示法下就是左式。代回原式可知复杂度为
O ( n 3 4 ln ⁡ n ) \mathcal O\left(\frac{n^{3\over 4}}{\ln n}\right) O(lnnn43)

min25 \texttt{min25} min25

复杂度即 h h h 计算中的求和次数和。这和 [ k ≠ 1 ]    f ( p i   k ) [k\ne 1]\;f(p_i^{\thinspace k}) [k=1]f(pik) 被计入的次数相同。

注意到递归的本质是搜索,可以设这个 f ( p i   k ) f(p_i^{\thinspace k}) f(pik) 实际上来自 f ( l ) f(l) f(l) 。设 l = m p i l=mp_i l=mpi,则 p i p_i pi 恰为 m m m 的最大质因子,因为 k ≠ 1 k\ne 1 k=1 。另一方面,设 big ⁡ ( x ) \operatorname{big}(x) big(x) x x x 的最大质因子,则 x big ⁡ ( x ) ⩽ s x\operatorname{big}(x)\leqslant s xbig(x)s 必须在 big ⁡ ( x ) \operatorname{big}(x) big(x) 处统计贡献。因此它的复杂度就是 ∑ i = 2 s [ i big ⁡ ( i ) ] ⩽ s \sum_{i=2}^{s}[i\operatorname{big}(i)]\leqslant s i=2s[ibig(i)]s

Lemma. 对于实数 α ∈ ( 0 , 1 ) \alpha\in(0,1) α(0,1),令 Q ( n ) = { i ⩽ n : big ⁡ ( i ) ⩽ i α } Q(n)=\{i\leqslant n:\operatorname{big}(i)\leqslant i^{\alpha}\} Q(n)={in:big(i)iα},则 ∣ Q ( n ) ∣ ∼ n ρ ( α − 1 ) |Q(n)|\sim n\rho(\alpha^{-1}) Q(n)nρ(α1),其中 ρ \rho ρ Dickman function \text{Dickman function} Dickman function [3]。

若令 M ( n ) = { i : i big ⁡ ( i ) ⩽ n } M(n)=\{i:i\operatorname{big}(i)\leqslant n\} M(n)={i:ibig(i)n},则 ∀ a ∈ ( 0 , 1 ) ,    ∣ M ( n ) ∣ = Ω ( n α ) \forall a\in(0,1),\;|M(n)|=\Omega(n^\alpha) a(0,1),M(n)=Ω(nα) 。因为 Lemma \text{Lemma} Lemma 告诉我们 P = { i ⩽ n α : big ⁡ ( i ) ⩽ n 1 − α } P=\{i\leqslant n^\alpha:\operatorname{big}(i)\leqslant n^{1-\alpha}\} P={inα:big(i)n1α} 的大小是 Ω ( n α ) \Omega(n^\alpha) Ω(nα),而 P ⊆ M ( n ) P\subseteq M(n) PM(n)

另一方面,取 t = ⌈ log ⁡ log ⁡ n ⌉ t=\lceil\log\log n\rceil t=loglogn,则 { x ⩽ n : big ⁡ ( x ) ⩽ p t } \{x\leqslant n:\operatorname{big}(x)\leqslant p_t\} {xn:big(x)pt} 大小不超过 ( log ⁡ n ) t = o ( n log ⁡ log ⁡ n ) (\log n)^t=o({n\over\log\log n}) (logn)t=o(loglognn),因为每个质因数的次数不超过 log ⁡ n \log n logn 。而其他的 i big ⁡ ( i ) ⩽ n i\operatorname{big}(i)\leqslant n ibig(i)n 的数满足 i ⩽ n p t ⩽ n log ⁡ log ⁡ n i\leqslant{n\over p_t}\leqslant{n\over\log\log n} iptnloglognn,因此 ∣ M ( n ) ∣ = O ( n log ⁡ log ⁡ n ) |M(n)|=\mathcal O({n\over\log\log n}) M(n)=O(loglognn)

于是乎,我们得到 ∣ M ( n ) ∣ = Θ ( n 1 − ϵ ) |M(n)|=\Theta(n^{1-\epsilon}) M(n)=Θ(n1ϵ) 。也就是说,它的渐进复杂度是错误的(从严格的数学意义上)。

Comment. 这里 n 1 − ϵ n^{1-\epsilon} n1ϵ 指优于 n n n 又劣于 n α    ( α < 1 ) n^\alpha\;(\alpha<1) nα(α<1),应该容易理解。

但是打表发现, n ⩽ 1 0 13 n\leqslant 10^{13} n1013 时,对于 p ⩽ n 1 / 4 p\leqslant n^{1/4} pn1/4,满足 big ⁡ ( i ) = p \operatorname{big}(i)=p big(i)=p i i i 的个数是 n \sqrt{n} n 级别的,而一共只有 O ( n 1 / 4 ln ⁡ n ) \mathcal O(\frac{n^{1/4}}{\ln n}) O(lnnn1/4) p p p,因此其提供的贡献是 n 3 / 4 ln ⁡ n n^{3/4}\over\ln n lnnn3/4 的 [3]。对于 big ⁡ ( i ) ⩾ n 1 / 4 \operatorname{big}(i)\geqslant n^{1/4} big(i)n1/4 不难发现其提供贡献是 O ( n 3 / 4 ln ⁡ n ) \mathcal O({n^{3/4}\over\ln n}) O(lnnn3/4) 的。

一句话:渐进复杂度是错误的,但是它跑得足够快。

洲阁筛

这就很简单了。质数密度 π ( n ) ≃ n ln ⁡ n \pi(n)\simeq{n\over\ln n} π(n)lnnn,很容易看出 ∑ j = 2 ⌊ log ⁡ 2 n ⌋ π ( w j ) = o ( π ( n ) ) \sum_{j=2}^{\lfloor\log_2 n\rfloor}\pi(\sqrt[j]{w})=o(\pi(n)) j=2log2nπ(jw )=o(π(n)),因此复杂度为
∑ w = 1 n ∑ j = 1 log ⁡ w π ( n / w j ) = O ( ∑ w = 1 n π ( w ) ) = O ( n 3 / 4 ln ⁡ n ) \sum_{w=1}^{\sqrt n}\sum_{j=1}^{\log w}\pi\left(\sqrt[j]{n/w}\right) =\mathcal O\left(\sum_{w=1}^{\sqrt{n}}\pi(w)\right) =\mathcal O\left({n^{3/4}\over\ln n}\right) w=1n j=1logwπ(jn/w )=O w=1n π(w) =O(lnnn3/4)

这就是所谓 “质数的幂的数量是很少的——相较于质数而言”。

z z t \sf zzt zzt 求和法

源自 [4],也可以参阅 [5] 获得更多信息。

若原函数在素数处的取值可以被易于计算前缀和的数论函数拟合,则可以用该方法。后面会说到,这种方法有 min25 \texttt{min25} min25 筛的影子。

前置知识:狄利克雷生成函数和杜教筛

考虑 D i r i c h l e t \rm Dirichlet Dirichlet 双曲线法计算 f ∗ g f*g fg 在所有 ⌊ n v ⌋ \lfloor{n\over v}\rfloor vn 位置的前缀和。若 f , g f,g f,g 的非零项密度为 O ( 1 ln ⁡ n ) \mathcal O({1\over\ln n}) O(lnn1),则计算 f ∗ g f*g fg 的前 x x x 项的和的复杂度是 x ln ⁡ n {\sqrt x\over\ln n} lnnx ,故总复杂度是
∑ x = 1 ⌊ n S ⌋ n x ln ⁡ n = O ( n 2 / 3 S ln ⁡ n ) \sum_{x=1}^{\lfloor{n\over S}\rfloor}{\sqrt{n\over x}\over\ln n}=\mathcal O\left({n^{2/3}\over\sqrt{S}\ln n}\right) x=1Snlnnxn =O(S lnnn2/3)

而前 S S S 项是狄利克雷卷积求出的,则复杂度为 O ( S log ⁡ S ln ⁡ 2 n ) \mathcal O({S\log S\over\ln^2 n}) O(ln2nSlogS) 。仍取 S = n 2 / 3 S=n^{2/3} S=n2/3,但复杂度已经是 O ( n 2 / 3 ln ⁡ n ) \mathcal O({n^{2/3}\over\ln n}) O(lnnn2/3) 了,而且不基于线性筛(不基于积性)。

考虑狄利克雷生成函数,设 F p F_p Fp 为质数 p p p 上的狄利克雷生成函数,则
F ( x ) = [ ∏ p ⩽ n 1 / 6 F p ( x ) ] [ ∏ n 1 / 6 < p ⩽ n 1 / 2 F p ( x ) ] [ ∏ n 1 / 2 < p F p ( x ) ] F(x)=\left[\prod_{p\leqslant n^{1/6}}F_p(x)\right] \left[\prod_{n^{1/6}<p\leqslant n^{1/2}}F_p(x)\right] \left[\prod_{n^{1/2}<p}F_p(x)\right] F(x)= pn1/6Fp(x) n1/6<pn1/2Fp(x) n1/2<pFp(x)

先求第二部分。

定理:恰含 k k k 个质因子,且最小质因子至少为 n α    ( α < 0.5 ) n^\alpha\;(\alpha<0.5) nα(α<0.5) n n n 以内的数的个数是 O [ ( α − 1 − 1 ) k n ln ⁡ − 1 n ] \mathcal O[(\alpha^{-1}{-}1)^kn\ln^{-1}n] O[(α11)knln1n] 。简记为 ϕ k ( n α , n ) \phi_k(n^\alpha,n) ϕk(nα,n)

证明:当 k = 1 k=1 k=1 时显然成立。归纳法,枚举最小质因子 x ∈ [ 2 , n ] x\in[2,\sqrt{n}] x[2,n ],则 ϕ k ( x , n x ) = O ( ( α − 1 − 1 ) k n x log ⁡ x ) \phi_k(x,{n\over x})=\mathcal O(\frac{(\alpha^{-1}{-}1)^kn}{x\log x}) ϕk(x,xn)=O(xlogx(α11)kn),于是估算
ϕ k + 1 ( n α , n ) ≈ ∫ n α n d x ln ⁡ x ( α − 1 − 1 ) k ⋅ n x ln ⁡ x = O [ ( α − 1 − 1 ) k + 1 n ln ⁡ − 1 n ] \phi_{k+1}(n^{\alpha},n)\approx \int_{n^\alpha}^{\sqrt{n}}\frac{\text{d}x}{\ln x}\frac{(\alpha^{-1}{-}1)^k\cdot n}{x\ln x} =\mathcal O[(\alpha^{-1}{-}1)^{k+1}n\ln^{-1}n] ϕk+1(nα,n)nαn lnxdxxlnx(α11)kn=O[(α11)k+1nln1n]

即证。 ■ \blacksquare

为了叙述方便,设第二部分对应的积性函数是 f 2 ( x ) f_2(x) f2(x),并记 P 2 = P ∩ ( n 1 / 6 , n 1 / 2 ] \mathbb P_2=\mathbb P\cap(n^{1/6},n^{1/2}] P2=P(n1/6,n1/2]

考虑忽略质因子顺序,每次任选某个质数,将其指数加一。设非积性的函数 inc ( p ) = [ p ∈ P 2 ]    f 2 ( p ) \text{inc}(p)=[p\in\mathbb P_2]\;f_2(p) inc(p)=[pP2]f2(p),我们从 inc ( x ) \text{inc}(x) inc(x) 开始,递推求出 inc k + 1 = inc k ∗ inc    ( k ⩾ 1 ) \text{inc}^{k+1}=\text{inc}^k\ast\text{inc}\;(k\geqslant 1) inck+1=inckinc(k1)

由定理一知 inc k ( x ) \text{inc}^k(x) inck(x) 非零项密度是 O ( 1 ln ⁡ n ) \mathcal O({1\over\ln n}) O(lnn1) 。因此这样乘法的复杂度是 O ( n 2 / 3 ln ⁡ n ) \mathcal O({n^{2/3}\over\ln n}) O(lnnn2/3) 。注意 k ⩽ ⌊ 1 α ⌋ k\leqslant \lfloor{1\over\alpha}\rfloor kα1 是常数,因此可以全部求出。

将它们累加,得到 g ( x ) = ∑ k ⩾ 1 g k ( x ) g(x)=\sum_{k\geqslant 1}g_k(x) g(x)=k1gk(x) 。设 n = ∏ p i t i n=\prod p_i^{t_i} n=piti,不难发现,其值是二项式系数 g ( n ) = ( ∑ t i ) ! ∏ ( t i ! ) ∏ inc ( p i ) t i g(n)={(\sum t_i)!\over\prod(t_i!)}\prod\text{inc}(p_i)^{t_i} g(n)=(ti!)(ti)!inc(pi)ti

于是构造积性函数 fit ( p t ) = inc ( p ) t ( t ! ) − 1    ( p ∈ P 2 ) \text{fit}(p^t)=\text{inc}(p)^t(t!)^{-1}\;(p\in\mathbb P_2) fit(pt)=inc(p)t(t!)1(pP2),我们求出 g ( n ) ( ∑ t i ) ! {g(n)\over(\sum t_i)!} (ti)!g(n) fit ( x ) \text{fit}(x) fit(x) 的前缀和。注意到 fit ( p ) = inc ( p ) = f 2 ( p ) \text{fit}(p)=\text{inc}(p)=f_2(p) fit(p)=inc(p)=f2(p),因此用 powerful number \text{powerful number} powerful number 的方法,可以 O ( n ) \mathcal O(\sqrt{n}) O(n ) fit \text{fit} fit 前缀和过渡到 f 2 f_2 f2 的前缀和。

先考虑怎么算第一部分。直接依次加入质数即可。每次加入时 O ( n log ⁡ p n ) \mathcal O(\sqrt{n}\log_p n) O(n logpn) 暴力更新,复杂度
∑ p ∈ P 1 n log ⁡ p n ∼ ∫ 1 n 1 / 6 d p ln ⁡ n n log ⁡ p n ∼ n li ⁡ ( n 1 / 6 ) = O ( n 2 / 3 ln ⁡ n ) \sum_{p\in\mathbb P_1}\sqrt{n}\log_p n\sim\int_{1}^{n^{1/6}}\frac{\text{d}p}{\ln n}\sqrt{n}\log_p n\\ \sim\sqrt{n}\operatorname{li}(n^{1/6})=\mathcal O\left({n^{2/3}\over\ln n}\right) pP1n logpn1n1/6lnndpn logpnn li(n1/6)=O(lnnn2/3)

怎么算第三部分。用易于求解前缀和的数论函数来拟合之,用类似 min25 \texttt{min25} min25 的方式,筛掉小质数。但是我们直接求出小质数对应的积性函数,则可以用上面的方法(第二部分 + + + 第一部分)做到 O ( n 2 / 3 log ⁡ n ) \mathcal O({n^{2/3}\over\log n}) O(lognn2/3)

Comment. 若对 p < n p<\sqrt{n} p<n 直接依次加入,则复杂度是 O ( n 3 / 4 log ⁡ n ) \mathcal O({n^{3/4}\over\log n}) O(lognn3/4) 的。这似乎就是 min25 \texttt{min25} min25 呢(枚举每个小质数并更新 O ( n ) \mathcal O(\sqrt{n}) O(n ) 个前缀和值),但是这就不再要求是积性函数了。估计跟第二部分原理相同

然后现在的问题是,知 f 3 ∗ a 1 = a 2 f_3\ast a_1=a_2 f3a1=a2,反推 f 3 f_3 f3 。由于 f 3 f_3 f3 [ 1 , n ] [1,\sqrt{n}] [1,n ] 内只有 f 3 ( 1 ) = 1 f_3(1)=1 f3(1)=1,因此算 w w w 前缀和时,需要枚举的部分只有 O ( w n ) \mathcal O({w\over\sqrt n}) O(n w) 长,易知其复杂度为 O ( n log ⁡ n ) \mathcal O(\sqrt{n}\log n) O(n logn)

算出来 f 3 f_3 f3 后,我们将其与 f 1 ∗ f 2 f_1\ast f_2 f1f2 合并。仍然利用 f 3 f_3 f3 [ 1 , n ] [1,\sqrt{n}] [1,n ] 内只有 f 3 ( 1 ) = 1 f_3(1)=1 f3(1)=1 非零的性质,合并还是 O ( n log ⁡ n ) \mathcal O(\sqrt{n}\log n) O(n logn) 的。

所以我们得到了总复杂度为 O ( n 2 / 3 log ⁡ n ) \mathcal O({n^{2/3}\over\log n}) O(lognn2/3) 的,素数处取值是多项式的积性函数的求和法。但是,据原作者说,这个做法并没有效率提升 😂

SBT \text{SBT} SBT 割线法

由于我能力较弱,这里就只做实用主义的探讨。

算法最初的目标是,求解 σ 0 ( n ) = ∑ d ∣ n 1 \sigma_0(n)=\sum_{d\mid n}1 σ0(n)=dn1 约数个数函数的前缀和。

方案是,用折线去拟合曲线 x y = n xy=n xy=n,使得曲线下方(含边界)的整点就是折线下方(不含边界)的全体整点。

仍然用 D i r i c h l e t \rm Dirichlet Dirichlet 双曲线法,则 x , y ⩽ n x,y\leqslant\sqrt{n} x,yn 部分 O ( 1 ) \mathcal O(1) O(1) 即得,因此只需计算 y ⩽ n y\leqslant\sqrt{n} yn 的部分。

x = ⌈ n + 1 y ⌉ ,    y = 1 + ⌊ n ⌋ x=\lceil{n+1\over y}\rceil,\;y=1+\lfloor{\sqrt n}\rfloor x=yn+1,y=1+n 开始,每次找正整数 p , q p,q p,q 满足 ( x + p ) ( y − q ) > n (x{+}p)(y{-}q)>n (x+p)(yq)>n,让 q p q\over p pq 最大的前提下最小化 p p p 。特别地,若 y = 1 y=1 y=1 则终止该过程。不难发现这样得到的折线符合要求且唯一存在。

怎么找?利用 Stern-Brocot Tree \text{Stern-Brocot Tree} Stern-Brocot Tree 即可。其简单讲解在此。

一个重要的点在于,判断某子树内是否还有可能会用到的斜率。也就是说,目前得到两个分数 a b , c d {a\over b},{c\over d} ba,dc,已知 a b a\over b ba 可行而 c d c\over d dc 不可行,问是否存在互质的正整数 p , q p,q p,q 使得 p a + q c p b + q d \frac{pa+qc}{pb+qd} pb+qdpa+qc 可行。

代码给出的判断是:若 ( x + d ) 2 ⋅ a ⩾ n ⋅ b (x{+}d)^2\cdot a\geqslant n\cdot b (x+d)2anb 就停止。尚不清楚其原理。

这个做法被证明是 O ~ ( n 1 / 3 ) \tilde{\mathcal O}(n^{1/3}) O~(n1/3) 的,最多是 O ( n 1 / 3 log ⁡ 3 n ) \mathcal O(n^{1/3}\log^3 n) O(n1/3log3n) 的,据称可被证明是 O ( n 1 / 3 log ⁡ n ) \mathcal O(n^{1/3}\log n) O(n1/3logn)

补充信息

这道题是非积性函数,也可以做。内有递推版代码。

据说 min25 \texttt{min25} min25 有了新版,不知道啥情况,这里只 m a r k \rm mark mark 一下。

R e f e r e n c e \rm Reference Reference

[1] jokerwyt. Min 25筛入门[EB/OL]. blog.csdn.net/j….

[2] GuessYCB. 关于min_25筛的一些理解[EB/OL]. cnblogs.com/G….

[3] 朱震霆. 一些特殊的数论函数求和问题[EB/OL]. private-link.

[4] whzzt. 积性函数求和问题的一种筛法[EB/OL]. blog.csdn.net/w….

[5] negiizhao. zzt求和法的简化版. negiizhao.blog.uoj.ac/blog/7165.

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值