前言

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

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

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

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

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

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

  • 第一步,求出质数 ppp 对应的 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)(p∈P) 不变。因为 step one\text{step one}step one 只需要求出 ∑p∈Pf(p)\sum_{p\in\mathbb{P}}f(p)∑p∈P​f(p) 。

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

用 g(n,j)g(n,j)g(n,j) 表示 [2,n][2,n][2,n] 去除前 jjj 个质数的倍数之后,剩余数字的 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} 为从小到大的质数(角标从 111 开始),则
g(n,j)=∑i=1jf(pi)+∑i=1n[p1∤i∧p2∤i∧⋯∧pj∤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=1∑j​f(pi​)+i=1∑n​[p1​∤i∧p2​∤i∧⋯∧pj​∤i]f(i)

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

考虑 dp\tt dpdp 求解。转移过程就是去掉 kpj(k>1)kp_j\;(k>1)kpj​(k>1) 。显然 kkk 不应该是前 (j−1)(j{\rm-}1)(j−1) 个质数的倍数,因为那是已经被移除的数。又因为 f(x)f(x)f(x) 是完全积性函数,有 f(kpj)=f(pj)f(k)f(kp_j)=f(p_j)f(k)f(kpj​)=f(pj​)f(k),于是有转移式
g(n,j)=g(n,j−1)−f(pj)[g(⌊npj⌋,j−1)−sumf⁡(j−1)](pj⩽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,j−1)−f(pj​)[g(⌊pj​n​⌋,j−1)−sumf(j−1)](pj​⩽n​)

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

特别地,如果 n<pj2n<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,j−1) 。若在 jjj 这一维上做滚动数组,则无需修改这些位置。同时可知,需要的质数最大是 n\sqrt nn​,所以直接线性筛即可求出 sumf⁡\operatorname{sumf}sumf 了。

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

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

nnn 的范围很大。注意到求解 g(n,j)g(n,j)g(n,j) 时,只递归到 n′=⌊nv⌋n'=\lfloor{n\over v}\rfloorn′=⌊vn​⌋ 的值;最后我们会看到,若求解 sss 长度的前缀和,则我们只需求出 n=⌊sv⌋(v∈N+)n=\lfloor{s\over v}\rfloor\;(v\in\N^+)n=⌊vs​⌋(v∈N+) 的答案,这样的 nnn 只有 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​ 的!于是咱可以枚举这玩意儿。记 xxx 的最小质因数为 γ(x)(x⩾2)\gamma(x)\;(x\geqslant 2)γ(x)(x⩾2) 。

记 h(n,j)=∑i=2n[γ(i)⩾pj]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⁡pin⌋f(pik)[h(⌊npik⌋,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(j−1)+i⩾j∑​k=1∑⌊logpi​​n⌋​f(pik​)[h(⌊pik​n​⌋,i+1)+[k=1]]

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

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

洲阁筛

令 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⁡pjn⌋f(pjk)[h(⌊ipjk⌋,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=1∑⌊logpj​​n⌋​f(pjk​)[h(⌊pjk​i​⌋,k+1)−sumf(j)+[k=1]]

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

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

代码实现

嗯,直接上代码。以板题 f(pk)=pk⋅(pk−1)f(p^k)=p^k\cdot (p^k{-}1)f(pk)=pk⋅(pk−1) 为例:需要用 x2x^2x2 和 xxx 分别拟合,于是将 ggg 设为 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 indexfor(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 itllong 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) 的,只算转移次数。每个 www 要用到不超过 w\sqrt{w}w​ 的质数,所以复杂度约为

∑i=1nniln⁡ni≈∫1nnxln⁡(nx)dx\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=1∑n​​lnin​​in​​​≈∫1n​​x​ln(xn​)n​​dx

2021/8/1update\tt 2021/8/1\;update2021/8/1update:由于被 HandInDevil\sf HandInDevilHandInDevil 臭骂了一顿,稍微讲讲用积分计算复杂度的事儿。它实际上是将数论函数的求和,转化为了连续函数的积分。这是否能作为渐进复杂度呢?

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

现在回到正题上。由于我已知道了结果,我告诉你
∫1xln⁡(nx)dx=O[xln⁡(nx)]\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​)1​dx=O[ln(xn​)x​​]

因为 ln⁡x\ln xlnx 型函数作分母比较特殊:右式的导数实际上是 12xln⁡(nx)+1xln⁡2(nx)\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 OO 表示法下就是左式。代回原式可知复杂度为
O(n34ln⁡n)\mathcal O\left(\frac{n^{3\over 4}}{\ln n}\right) O(lnnn43​​)

min25\texttt{min25}min25 筛

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

注意到递归的本质是搜索,可以设这个 f(pik)f(p_i^{\thinspace k})f(pik​) 实际上来自 f(l)f(l)f(l) 。设 l=mpil=mp_il=mpi​,则 pip_ipi​ 恰为 mmm 的最大质因子,因为 k≠1k\ne 1k=1 。另一方面,设 big⁡(x)\operatorname{big}(x)big(x) 为 xxx 的最大质因子,则 xbig⁡(x)⩽sx\operatorname{big}(x)\leqslant sxbig(x)⩽s 必须在 big⁡(x)\operatorname{big}(x)big(x) 处统计贡献。因此它的复杂度就是 ∑i=2s[ibig⁡(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)={i⩽n: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:ibig⁡(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)⩽n1−α}P=\{i\leqslant n^\alpha:\operatorname{big}(i)\leqslant n^{1-\alpha}\}P={i⩽nα:big(i)⩽n1−α} 的大小是 Ω(nα)\Omega(n^\alpha)Ω(nα),而 P⊆M(n)P\subseteq M(n)P⊆M(n) 。

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

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

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

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

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

洲阁筛

这就很简单了。质数密度 π(n)≃nln⁡n\pi(n)\simeq{n\over\ln n}π(n)≃lnnn​,很容易看出 ∑j=2⌊log⁡2n⌋π(wj)=o(π(n))\sum_{j=2}^{\lfloor\log_2 n\rfloor}\pi(\sqrt[j]{w})=o(\pi(n))∑j=2⌊log2​n⌋​π(jw​)=o(π(n)),因此复杂度为
∑w=1n∑j=1log⁡wπ(n/wj)=O(∑w=1nπ(w))=O(n3/4ln⁡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=1∑n​​j=1∑logw​π(jn/w​)=O⎝⎛​w=1∑n​​π(w)⎠⎞​=O(lnnn3/4​)

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

zzt\sf zztzzt 求和法

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

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

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

考虑 Dirichlet\rm DirichletDirichlet 双曲线法计算 f∗gf*gf∗g 在所有 ⌊nv⌋\lfloor{n\over v}\rfloor⌊vn​⌋ 位置的前缀和。若 f,gf,gf,g 的非零项密度为 O(1ln⁡n)\mathcal O({1\over\ln n})O(lnn1​),则计算 f∗gf*gf∗g 的前 xxx 项的和的复杂度是 xln⁡n{\sqrt x\over\ln n}lnnx​​,故总复杂度是
∑x=1⌊nS⌋nxln⁡n=O(n2/3Sln⁡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=1∑⌊Sn​⌋​lnnxn​​​=O(S​lnnn2/3​)

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

考虑狄利克雷生成函数,设 FpF_pFp​ 为质数 ppp 上的狄利克雷生成函数,则
F(x)=[∏p⩽n1/6Fp(x)][∏n1/6<p⩽n1/2Fp(x)][∏n1/2<pFp(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)=⎣⎡​p⩽n1/6∏​Fp​(x)⎦⎤​⎣⎡​n1/6<p⩽n1/2∏​Fp​(x)⎦⎤​⎣⎡​n1/2<p∏​Fp​(x)⎦⎤​

先求第二部分。

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

证明:当 k=1k=1k=1 时显然成立。归纳法,枚举最小质因子 x∈[2,n]x\in[2,\sqrt{n}]x∈[2,n​],则 ϕk(x,nx)=O((α−1−1)knxlog⁡x)\phi_k(x,{n\over x})=\mathcal O(\frac{(\alpha^{-1}{-}1)^kn}{x\log x})ϕk​(x,xn​)=O(xlogx(α−1−1)kn​),于是估算
ϕk+1(nα,n)≈∫nαndxln⁡x(α−1−1)k⋅nxln⁡x=O[(α−1−1)k+1nln⁡−1n]\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​​lnxdx​xlnx(α−1−1)k⋅n​=O[(α−1−1)k+1nln−1n]

即证。■\blacksquare■

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

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

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

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

于是构造积性函数 fit(pt)=inc(p)t(t!)−1(p∈P2)\text{fit}(p^t)=\text{inc}(p)^t(t!)^{-1}\;(p\in\mathbb P_2)fit(pt)=inc(p)t(t!)−1(p∈P2​),我们求出 g(n)(∑ti)!{g(n)\over(\sum t_i)!}(∑ti​)!g(n)​ 为 fit(x)\text{fit}(x)fit(x) 的前缀和。注意到 fit(p)=inc(p)=f2(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 前缀和过渡到 f2f_2f2​ 的前缀和。

先考虑怎么算第一部分。直接依次加入质数即可。每次加入时 O(nlog⁡pn)\mathcal O(\sqrt{n}\log_p n)O(n​logp​n) 暴力更新,复杂度
∑p∈P1nlog⁡pn∼∫1n1/6dpln⁡nnlog⁡pn∼nli⁡(n1/6)=O(n2/3ln⁡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) p∈P1​∑​n​logp​n∼∫1n1/6​lnndp​n​logp​n∼n​li(n1/6)=O(lnnn2/3​)

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

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

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

算出来 f3f_3f3​ 后,我们将其与 f1∗f2f_1\ast f_2f1​∗f2​ 合并。仍然利用 f3f_3f3​ 在 [1,n][1,\sqrt{n}][1,n​] 内只有 f3(1)=1f_3(1)=1f3​(1)=1 非零的性质,合并还是 O(nlog⁡n)\mathcal O(\sqrt{n}\log n)O(n​logn) 的。

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

【学习笔记】特殊数论函数求和相关推荐

  1. MATLAB学习笔记:数列求和与级数

    数列求和命令一:sum(x) 例1: x为向量: >> a=[1 2 3]a =1 2 3>> sum(a)ans =6 例2: x为矩阵: >> b=[1 2 3 ...

  2. 前端学习笔记-07post请求和get请求,样式以及CSS

    1.get请求和post请求的区别 2. style属性 通过设置style属性来改变样式 案例:使用style属性优化登录表单 <!DOCTYPE html> <html>& ...

  3. python分组求和_Python学习笔记之pandas索引列、过滤、分组、求和功能示例

    本文实例讲述了Python学习笔记之pandas索引列.过滤.分组.求和功能.分享给大家供大家参考,具体如下: 前面我们已经把519961(基金编码)这种基金的历史净值明细表html内容抓取到了本地, ...

  4. PHP学习笔记02:自然数列求和

    PHP学习笔记02:自然数列求和 1.在d:\xampp\htdocs里创建文件demo02.php 2.编写源代码 <!DOCTYPE html><head><titl ...

  5. 模电学习笔记(五)——反相求和电路

    模电学习笔记(五) 反相求和电路设计 如下图就是一个反相求和电路设计拓扑 同个例子来说明如何设计反相求和电路 设计目标: 输入1(V) 输入2(V) 输出(V) 频率(kHz) 电源(V) 最小 最大 ...

  6. Hadoop学习笔记一 简要介绍

    Hadoop学习笔记一 简要介绍 这里先大致介绍一下Hadoop.     本文大部分内容都是从官网Hadoop上来的.其中有一篇介绍HDFS的pdf文档,里面对Hadoop介绍的比较全面了.我的这一 ...

  7. Numpy学习笔记(下篇)

    目录 Numpy学习笔记(下篇) 一.Numpy数组的合并与分割操作 1.合并操作 2.分割操作 二.Numpy中的矩阵运算 1.Universal Function 2.矩阵运算 3.向量和矩阵运算 ...

  8. Lua学习笔记6:C++和Lua的相互调用

    曾经一直用C++写代码.话说近期刚换工作.项目组中的是cocos2dx-lua,各种被虐的非常慘啊有木有. 新建cocos2dx-lua项目.打开class能够发现,事实上就是C++项目啦,只是为什么 ...

  9. 一文弄懂元学习 (Meta Learing)(附代码实战)《繁凡的深度学习笔记》第 15 章 元学习详解 (上)万字中文综述

    <繁凡的深度学习笔记>第 15 章 元学习详解 (上)万字中文综述(DL笔记整理系列) 3043331995@qq.com https://fanfansann.blog.csdn.net ...

  10. 【学习笔记】线性代数全家桶(在编程竞赛中的应用)

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 目录 0x00. 矩阵 0x01. 矩阵 0x02. 矩阵的加法与数量乘法 0x03. 矩阵乘法 0x ...

最新文章

  1. 题目1188:约瑟夫环
  2. Edit Distance Python源码及支持包的实现
  3. [BUUCTF]PWN——ciscn_2019_es_2(栈劫持)
  4. mysql增加sort_buffer_设置sort_buffer_size
  5. C++ 内存对齐 及 引用是否真的节省内存的一点思考
  6. c语言 关键字const_C ++ const关键字| 查找输出程序| 套装1
  7. Chart.js学习
  8. 小括号教学设计导入_人教版一年级数学下教案 《小括号》教案
  9. Atitit 虚拟经济世代 与 知识管理
  10. 整理六百篇web前端知识混总
  11. 导出手机QQ聊天记录到电脑
  12. 历史经验之js个200经验收藏
  13. Elasticsearch 使用初级入门 【入门篇】
  14. win10用linux命令关机,Win7、Win10和Ubuntu 都在用的关机命令
  15. 腾讯物联网云平台 密钥 MQTT参数生成及密码加密算法实现
  16. Android Google地图接入(二)
  17. TOEIC Speak 真题
  18. [Unity实战] UGUI 背景框(图片)尺寸自适应内容(图片、按钮、文字等)
  19. 复数抽象数据类型及其四则运算 (c++)
  20. 每日技巧(word条形图更改横坐标)

热门文章

  1. 如何用ps设计出一张吸引人眼球的创意节日海报?
  2. windows如何设置默认“大图标”显示
  3. Python多线程-手慢无的真相
  4. stm32不使用外部晶振管脚怎么处理_stm32103如果不用32k晶振,那引脚是悬空还是接地?...
  5. 一文读懂什么是EPP、EDR、CWPP、HIDS及业内主流产品
  6. excel函数提取计算机登录名,Excel查找函数FIND,帮你从复杂的地址中提取城市、区和街道名!-提取文件名...
  7. RNA-seq流程学习笔记(4)-使用FastQC软件对fastq格式的数据进行质量控制
  8. 4、Flutter - 控件基础 (二)ListView 列表展示数据、布局
  9. 洛谷P1379八数码难题
  10. SSL证书怎么部署,SSL证书需要怎么安装你知道吗?