筛法学习笔记

埃氏筛

枚举质数 \(p_i\) ,每次去除所有是 \(p_i\) 倍数的数,总效率大概是 \(O(n\log\log n)\)

int _prm=0,prm[M];bool isprm[M];
void Get_phi(int n){
	for(int i=2;i<=n;i++){
		if(isprm[i]) continue ;
		prm[++_prm]=i;
		for(int j=i*i;j<=n;j+=i) isprm[j]=1;
	}
}

值得一提的,可以通过模拟埃氏筛来快速求得区间素数,处理方式和 Min_25 筛的一部分很像。

线性筛

自行理解吧(

int _prm=0,prm[M];bool isprm[M];
void Pri(int n){
	for(int i=2;i<=n;i++){
		if(!isprm[i]) prm[++_prm]=i;
		for(int j=1;j<=_prm&&i*prm[j]<=n;j++){
			isprm[i*prm[j]]=1;
			if(i%prm[j]==0) break;
		}
	}
}

杜教筛

给出一个积性函数 \(f(x)\) ,求出 \(S(n)=\sum\limits_{i=1}^n f(i)\)

\(n\le 10^9\)

利用狄利克雷卷积,找出一个积性函数 \(g(x)\)

\[\begin{aligned} \end{aligned} \]

\[\begin{aligned} \sum\limits_{i=1}^n (f*g)(i)=\sum\limits_{i=1}^n \sum\limits_{d|i} f(d)\times g(\frac{i}{d}) \end{aligned} \]

\[\begin{aligned} =\sum\limits_{d=1}^n g(d) \sum\limits_{i=1}^{⌊\frac{n}{d}⌋} f(i) \end{aligned} \]

\[\begin{aligned} =\sum\limits_{d=1}^n g(d)\times S(⌊\frac{n}{d}⌋) \end{aligned} \]

如果知道了 \(g(1)S(n)\)\(S(n)\) 自然也可以求出来。

\[\begin{aligned} g(1)S(n)=\sum\limits_{d=1}^n g(d)\times S(⌊\frac{n}{d}⌋)-\sum\limits_{d=2}^n g(d)\times S(⌊\frac{n}{d}⌋) \end{aligned} \]

\[\begin{aligned} =\sum\limits_{i=1}^n (f*g)(i)-\sum\limits_{d=2}^n g(d)\times S(⌊\frac{n}{d}⌋) \end{aligned} \]

如果找的那个 \(g(x)\) 可以在很短的时间内算出\(g(x)\)\((f*g)(x)\) 的前缀和 ,那么就可以通过数论分块来递归求解。

假设求 \(g(x)\)\((f*g)(x)\) 的前缀和的复杂度为常数,总的复杂度为 \(\mathcal{O(n^{\frac{3}{4}})}\)

经典杜教筛套路

\[f(n)=μ(n)\ \ \ \ \ g(n)=1\ \ \ \ \ (f*g)(n)=[n==1] \]

int _prm=0,prm[M],mu[M],pre_mu[M];bool isprm[M];
void Get_Mu(int n){
	mu[1]=pre_mu[1]=1;
	for(int i=2;i<=n;i++){
		if(!isprm[i]) prm[++_prm]=i,mu[i]=-1;
		for(int j=1;j<=_prm&&i*prm[j]<=n;j++){
			isprm[i*prm[j]]=1;
			if(i%prm[j]==0) break;
			mu[i*prm[j]]=-mu[i];
		}
		pre_mu[i]=pre_mu[i-1]+mu[i];
	}
}

map<int,int> Smu;
int Sum_mu(int n){
	if(n<M) return pre_mu[n];
	if(Smu[n]) return Smu[n];
	int res=1;
	for(int l=2,r=0;l<=n;l=r+1){
		r=(n/(n/l));
		res-=(r-l+1)*Sum_mu(n/l);
	}
	return Smu[n]=res;
}

\[f(n)=φ(n)\ \ \ \ \ g(n)=1\ \ \ \ \ (f*g)(n)=n \]

int _prm=0,prm[M],phi[M],pre_phi[M];bool isprm[M];
void Get_Phi(int n){
	phi[1]=pre_phi[1]=1;
	for(int i=2;i<=n;i++){
		if(!isprm[i]) prm[++_prm]=i,phi[i]=i-1;
		for(int j=1;j<=_prm&&i*prm[j]<=n;j++){
			isprm[i*prm[j]]=1;
			if(i%prm[j]==0){
				phi[i*prm[j]]=phi[i]*prm[j];
				break;
			}
			phi[i*prm[j]]=phi[i]*(prm[j]-1);
		}
		pre_phi[i]=pre_phi[i-1]+phi[i];
	}
}

map<int,int> Sphi;
int Sum_phi(int n){
	if(n<M) return pre_phi[n];
	if(Sphi[n]) return Sphi[n];
	int res=n*(n+1)/2;
	for(int l=2,r=0;l<=n;l=r+1){
		r=(n/(n/l));
		res-=(r-l+1)*Sum_phi(n/l);
	}
	return Sphi[n]=res;
}

\[f(n)=n×φ(n)\ \ \ \ \ g(n)=n\ \ \ \ \ (f*g)(n)=n^2 \]

Min_25筛

这是一个大力推一波不知有何用的式子,然后我也不知道怎么证明但是复杂度就是 \(\mathcal{O(\frac{n^{\frac{3}{4}}}{\log n})}\) 的神仙筛法。

posted @ 2024-04-12 21:48  Dabuliuzp  阅读(2)  评论(0编辑  收藏  举报
/* */ 返回顶端