欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 新车 > 杜教筛原理,实现与时间复杂度分析

杜教筛原理,实现与时间复杂度分析

2025/5/5 21:23:46 来源:https://blog.csdn.net/GaoGuohao2022/article/details/147702727  浏览:    关键词:杜教筛原理,实现与时间复杂度分析

引例

洛谷 P4213 【模板】杜教筛

题目描述

给定一个正整数,求

a n s 1 = ∑ i = 1 n φ ( i ) ans_1=\sum_{i=1}^n\varphi(i) ans1=i=1nφ(i)

a n s 2 = ∑ i = 1 n μ ( i ) ans_2=\sum_{i=1}^n \mu(i) ans2=i=1nμ(i)

输入格式

本题单测试点内有多组数据

输入的第一行为一个整数,表示数据组数 T T T

接下来 T T T 行,每行一个整数 n n n,表示一组询问。

输出格式

对于每组询问,输出一行两个整数,分别代表 a n s 1 ans_1 ans1 a n s 2 ans_2 ans2

输入输出样例 #1

输入 #1

6
1
2
8
13
30
2333

输出 #1

1 1
2 0
22 -2
58 -3
278 -3
1655470 2

说明/提示

数据规模与约定

对于全部的测试点,保证 1 ≤ T ≤ 10 1 \leq T \leq 10 1T10 1 ≤ n < 2 31 1 \leq n \lt 2^{31} 1n<231。对于全部的测试点,保证 1 ≤ T ≤ 10 1 \leq T \leq 10 1T10 1 ≤ n < 2 31 1 \leq n \lt 2^{31} 1n<231

题中要求以低于线性的时间复杂度对数论函数求和。

原理

将例写为更一般的形式:

S ( n ) = ∑ i = 1 n f ( i ) S(n)=\sum_{i=1}^{n}f(i) S(n)=i=1nf(i) ,其中, f f f 是数论函数。

构造函数 g g g 并令 h = f ∗ g = g ∗ f h=f*g=g*f h=fg=gf
故,
∑ i = 1 n h ( i ) = ∑ i = 1 n ∑ d ∣ i g ( d ) f ( i d ) = ∑ d = 1 n ∑ d ∣ i n g ( d ) f ( i d ) = ∑ d = 1 n g ( d ) ∑ d ∣ i n f ( i d ) = ∑ d = 1 n g ( d ) ∑ i = 1 ⌊ n / d ⌋ f ( i ) = ∑ d = 1 n g ( d ) S ( ⌊ n / d ⌋ ) = g ( 1 ) S ( n ) + ∑ i = 2 n g ( i ) S ( ⌊ n / i ⌋ ) \begin{align} \nonumber \sum_{i=1}^nh(i) \nonumber &=\sum_{i=1}^n\sum_{d|i}g(d)f(\frac id) \\ \nonumber &=\sum_{d=1}^n\sum_{d|i}^ng(d)f(\frac id) \\ \nonumber &=\sum_{d=1}^ng(d)\sum_{d|i}^nf(\frac id) \\ \nonumber &=\sum_{d=1}^ng(d)\sum_{i=1}^{\lfloor n/d\rfloor}f(i) \\ \nonumber &=\sum_{d=1}^ng(d)S(\lfloor n/d\rfloor) \\ \nonumber &=g(1)S(n)+\sum_{i=2}^ng(i)S(\lfloor n/i\rfloor) \nonumber \end{align} i=1nh(i)=i=1ndig(d)f(di)=d=1nding(d)f(di)=d=1ng(d)dinf(di)=d=1ng(d)i=1n/df(i)=d=1ng(d)S(⌊n/d⌋)=g(1)S(n)+i=2ng(i)S(⌊n/i⌋)
因此,
g ( 1 ) S ( n ) = ∑ i = 1 n h ( i ) − ∑ i = 2 n g ( i ) S ( ⌊ n / i ⌋ ) g(1)S(n)=\sum_{i=1}^nh(i)-\sum_{i=2}^ng(i)S(\lfloor n/i\rfloor) g(1)S(n)=i=1nh(i)i=2ng(i)S(⌊n/i⌋)

采用数论分块加速第二个求和运算,这要求:

  • 可以快速计算 ∑ i = 1 n h ( i ) \sum_{i=1}^nh(i) i=1nh(i)
  • 可以快速计算 ∑ i = l r g ( i ) \sum_{i=l}^rg(i) i=lrg(i)

实现

实现时构造出来的 h , g h,g h,g 已经满足了上述要求,采用记忆化搜索计算 S ( n ) S(n) S(n) ,数论分块加速求和。
众所周知, μ ∗ I = ϵ μ∗I=ϵ μI=ϵ φ ∗ I = i d φ∗I=id φI=id
–>To learn more about it
于是,带入到杜教筛公式中,
I ( 1 ) S ( n ) = ∑ i = 1 n ϵ ( i ) − ∑ i = 2 n I ( i ) S ( ⌊ n / i ⌋ ) I(1)S(n)=\sum_{i=1}^nϵ(i)-\sum_{i=2}^nI(i)S(\lfloor n/i\rfloor) I(1)S(n)=i=1nϵ(i)i=2nI(i)S(⌊n/i⌋)
I ( 1 ) S ( n ) = ∑ i = 1 n i d ( i ) − ∑ i = 2 n I ( i ) S ( ⌊ n / i ⌋ ) I(1)S(n)=\sum_{i=1}^nid(i)-\sum_{i=2}^nI(i)S(\lfloor n/i\rfloor) I(1)S(n)=i=1nid(i)i=2nI(i)S(⌊n/i⌋)
即,
S ( n ) = 1 − ∑ i = 2 n S ( ⌊ n / i ⌋ ) S(n)=1-\sum_{i=2}^nS(\lfloor n/i\rfloor) S(n)=1i=2nS(⌊n/i⌋)
S ( n ) = n ( n + 1 ) 2 − ∑ i = 2 n S ( ⌊ n / i ⌋ ) S(n)=\frac {n(n+1)}2-\sum_{i=2}^nS(\lfloor n/i\rfloor) S(n)=2n(n+1)i=2nS(⌊n/i⌋)
考虑进一步优化,对于前 k k k 项使用线性筛直接计算,可以证明 k = O ( n 2 / 3 ) k=O(n^{2/3}) k=O(n2/3) 最优(证明参见最后一部分)。
在实现中,一般使用 unordered_map/gp_hash_table 进行记忆化。由于常数较大,一般将预处理部分的 k k k 在不炸空间的情况下开得尽量大一些。
以下为C++参考实现,尽管全开了long long并且未经过卡常,常数依然中规中矩,完全可以接受。record link 。

#include <bits/stdc++.h>
#define int long long
using namespace std;const int K=5e6; 
int t,n,vh1[K],vh2[K];
bool notprime[K];
vector<int>prime;
unordered_map<int,int>s1,s2;inline int read(){int s=0;bool f=0;char c=getchar();while(!isdigit(c)){if(c=='-')f^=1;c=getchar();}while(isdigit(c)){s=(s<<1)+(s<<3)+(c^48);c=getchar();}return f==0?s:-s;
}void pre(){vh1[1]=1;vh2[1]=1;for(int i=2;i<K;++i){if(!notprime[i]){prime.push_back(i);vh1[i]=i-1;vh2[i]=-1;}for(int p:prime){if(i*p>=K)break;notprime[i*p]=1;vh1[i*p]=vh1[i]*vh1[p];vh2[i*p]=-vh2[i];if(i%p==0){vh1[i*p]=vh1[i]*p;vh2[i*p]=0; break;}}}for(int i=1;i<K;++i)vh1[i]+=vh1[i-1],vh2[i]+=vh2[i-1];
}int S1(int n){if(n<K)return vh1[n];if(s1[n]!=0)return s1[n];int res=(n+1)*n/2,l=2,r;while(l<=n){r=n/(n/l);res-=S1(n/l)*(r-l+1);l=r+1;}return s1[n]=res;
}int S2(int n){if(n<K)return vh2[n];if(s2[n]!=0)return s2[n];int res=1,l=2,r;while(l<=n){r=n/(n/l);res-=S2(n/l)*(r-l+1);l=r+1;}return s2[n]=res;
}signed main(){pre();t=read();while(t--){n=read();cout<<S1(n)<<" "<<S2(n)<<endl;}return 0;
}

时间复杂度分析

此处伪证极多,点名《算法竞赛》中的“高阶小量”伪证。

先考虑有哪些 S ( i ) S(i) S(i) 会被计算。
设记搜时 S ( i ) S(i) S(i) 会使用 R ( i ) = { j ∣ j = ⌊ i k ⌋ , k ∈ N + , k > 1 } R(i)=\{j|j=\lfloor \frac ik \rfloor,k∈\mathbb{N^+},k>1\} R(i)={jj=ki,kN+,k>1} 中的元素的 S S S

下证若 m ∈ R ( n ) m∈R(n) mR(n) ,则 R ( m ) ⊆ R ( n ) R(m)\subseteq R(n) R(m)R(n)
对于任意 i ∈ R ( m ) i∈R(m) iR(m) , i = ⌊ m x ⌋ i=\lfloor \frac mx \rfloor i=xm
m = ⌊ n y ⌋ m=\lfloor \frac ny \rfloor m=yn
i = ⌊ ⌊ n y ⌋ x ⌋ = ⌊ n x y ⌋ ∈ R ( n ) i=\lfloor \frac {\lfloor \frac ny \rfloor}x \rfloor =\lfloor \frac n{xy} \rfloor ∈R(n) i=xyn=xynR(n)

由上知只有 i ∈ R ( n ) i∈R(n) iR(n) 才会被计算。

下令 T ( n ) T(n) T(n) 为计算 S ( n ) S(n) S(n) 的时间复杂度,并忽略计算 h , g h,g h,g 相关的消耗。则由数论分块相关可知 T ( n ) = n T(n)=\sqrt n T(n)=n

类似数论分块,若 i = ⌊ n x ⌋ ∈ R ( n ) i=\lfloor \frac nx \rfloor∈R(n) i=xnR(n)
i ≤ n i≤\sqrt n in 或 $ i=\lfloor \frac nj \rfloor,j<\sqrt n$ 。

对于朴素的杜教筛(不使用线性筛优化),其时间复杂度为,
∑ i ∈ R ( n ) T ( i ) = ∑ i ∈ R ( n ) i = ∑ i = 1 ⌊ n ⌋ i + ∑ j = 2 ⌊ n ⌋ n j < ∑ i = 1 ⌊ n ⌋ i + n i ≈ ∫ 0 n ( x + n x ) d x = n 3 / 4 \begin{align} \nonumber \sum_{i∈R(n)}T(i)&=\sum_{i∈R(n)}\sqrt i \\ \nonumber &=\sum_{i=1}^{\lfloor \sqrt n \rfloor}\sqrt i + \sum_{j=2}^{\lfloor \sqrt n \rfloor}\sqrt \frac nj \\ \nonumber &<\sum_{i=1}^{\lfloor \sqrt n \rfloor}\sqrt i +\sqrt \frac ni \nonumber \\ &≈\int_0^{\sqrt n}(\sqrt x +\sqrt \frac nx)dx \nonumber \\ &=n^{3/4} \nonumber \end{align} iR(n)T(i)=iR(n)i =i=1n i +j=2n jn i=1n i +in 0n (x +xn )dx=n3/4
即为 O ( n 3 / 4 ) O(n^{3/4}) O(n3/4)

若使用线性筛预处理前 k k k 项,预处理部分时间复杂度为 O ( k ) O(k) O(k) 。当 k > n k>\sqrt n k>n 时时间复杂度变为,
k + ∑ i ∈ R ( n ) , i > k T ( i ) = k + ∑ i ∈ R ( n ) , i > k i = k + ∑ j = 2 ⌊ n / k ⌋ n j < k + ∑ i = 1 ⌊ n / k ⌋ n i ≈ k + ∫ 0 n / k n x d x = k + n k \begin{align} \nonumber k+\sum_{i∈R(n),i>k}T(i)&=k+\sum_{i∈R(n),i>k}\sqrt i \\ \nonumber &=k+ \sum_{j=2}^{\lfloor n/k \rfloor}\sqrt \frac nj \\ \nonumber &<k+\sum_{i=1}^{\lfloor n/k \rfloor}\sqrt \frac ni \nonumber \\ &≈k+\int_0^{n/k}\sqrt \frac nxdx \nonumber \\ &=k+\frac n{\sqrt k} \nonumber \end{align} k+iR(n),i>kT(i)=k+iR(n),i>ki =k+j=2n/kjn k+i=1n/kin k+0n/kxn dx=k+k n
为求上式极值,以 k k k 为自变量求导,令 d O d k = 1 − 1 2 n k − 3 2 = 0 \frac {dO}{dk}=1-\frac 12 nk^{-\frac 32}=0 dkdO=121nk23=0 ,
得到 k = O ( n 2 / 3 ) k=O(n^{2/3}) k=O(n2/3) ,此时总时间复杂度为 O ( n 2 / 3 ) O(n^{2/3}) O(n2/3)

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词