扩展埃氏筛入门

版权声明:随意转载哦......但还是请注明出处吧: https://blog.csdn.net/dreaming__ldx/article/details/91354726

感觉和 m i n _ 25 min\_25 筛挺像的???(大雾
听说貌似可以求很多东西的样子,于是就去入了个门(然而啥题都不会做。
参考博客:litble巨佬的与扩展埃氏筛(min_25筛?)玩耍

用拓展埃氏筛处理一些与素数有关的问题

e . g . 1 e.g.1 1 1 ~   n \ n 之间的素数个数, n 1 0 11 n\le10^{11}
传送门
貌似线性筛会 T L E TLE 啊(显而易见
然后就有了扩展埃氏筛这个东西。
我们考虑埃氏筛的过程:
现在最开始有一排数 1 , 2 , 3 , . . . , n 1,2,3,...,n ,我们只知道 1 1 不是质数,而并不知道 2 2 ~ n n 哪些不是质数,于是每次发现一个质数之后就会把它的倍数全部标记成为合数,之后访问到的没有打过标记的即为质数。
换到这道题上面:
我们令 f ( x ) f(x) 表示 1 1 ~   x \ x 之间的质数个数,由于最开始不知道哪些是合数,因此初始化时 f ( x ) = x 1 f(x)=x-1
之后直接往后枚举,假设现在正在处理质数 p p ,那么对于 f ( i ) f(i) 显然需要扣掉以 p p 为最小质因子的合数,也就是 f ( i p ) f ( p 1 ) f(\left\lfloor\frac{i}{p}\right\rfloor)-f(p-1) ,(因为此时 f ( i p ) f(\left\lfloor\frac{i}{p}\right\rfloor) 已经被处理过并且将小于 p p 的质数也算入内了因此要扣掉)
即: f ( i ) = f ( i p ) f ( p 1 ) f(i)-=f(\left\lfloor\frac{i}{p}\right\rfloor)-f(p-1)
那么我们用两个数组 f 1 , f 2 f1,f2 来记录 f f 的部分,其中 f 1 ( x ) = f ( x ) , f 2 ( x ) = f ( n / x ) f1(x)=f(x),f2(x)=f(n/x)
于是就可以处理了。

#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int N=1e6+5;
typedef long long ll;
ll f1[N],f2[N],n;
int lim;
int main(){
	cin>>n;
	lim=sqrt(n);
	for(ri i=1;i<=lim;++i)f1[i]=i-1,f2[i]=n/i-1;
	for(ri p=2;p<=lim;++p){
		if(f1[p]==f1[p-1])continue;
		for(ri i=1;i<=lim/p;++i)f2[i]-=f2[i*p]-f1[p-1];
		for(ri i=lim/p+1;(ll)i<=n/(ll)p/(ll)p&&i<=lim;++i)f2[i]-=f1[n/i/p]-f1[p-1];
		for(ri i=lim;i>=(ll)p*p;--i)f1[i]-=f1[i/p]-f1[p-1];
	}
	cout<<f2[1];
	return 0;
}

e . g . 2 e.g.2 计算给定区间内所有质数之和, L , R 1 0 10 L,R\le10^{10}
传送门
解法几乎同上。
f f 函数的递推式是 f ( i ) = ( f ( i p ) f ( p 1 ) ) p f(i)-=(f(\left\lfloor\frac{i}{p}\right\rfloor)-f(p-1))*p
建议初学者自己手推一下。
代码:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int N=1e6+5;
typedef long long ll;
const double eps=1e-12;
double f1[N],f2[N];
ll L,R;
inline double S(const ll&x){return (double)(x+1)*(double)x/2.0;}
inline double query(ll n){
	if(!n)return 0;
	ll lim=sqrt(n);
	for(ll i=1;i<=lim;++i)f1[i]=S(i),f2[i]=S(n/i);
	for(ll p=2;p<=lim;++p){
		if(fabs(f1[p]-f1[p-1])<eps)continue;
		double t=f1[p-1];
		for(ri i=1;i<=lim/p;++i)f2[i]-=(f2[i*p]-t)*(double)p;
		for(ll i=lim/p+1;i<=lim&&i<=n/p/p;++i)f2[i]-=(double)(f1[n/i/p]-t)*(double)p;
		for(ll i=lim;i>=p*p;--i)f1[i]-=(f1[i/p]-t)*(double)p;
	}
	return f2[1];
}
int main(){
	cin>>L>>R;
	printf("%.0lf",query(R)-query(L-1));
	return 0;
}

用拓展埃氏筛处理一些与积性函数有关的问题

e . g . 3 e.g.3
多组数据,求 S k ( n ) = i = 1 n σ 0 ( i k ) . S_k(n) = \sum _{i=1}^n \sigma_0(i^k).
满足 k , n 1 0 10 , σ 0 ( x ) k,n\le10^{10},\sigma_0(x) 表示 x x 的约数个数。
传送门
质数的处理挺简单的。
现在还需要处理合数。
考虑唯一分解定理,发现可以不断枚举当前可能的最小质因子的幂来统计答案。
可以看代码中的解析:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
	static char buf[rlen],*ib,*ob;
	(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
	return ib==ob?-1:*ib++;
}
typedef unsigned long long ll;
inline ll read(){
	ll ans=0;
	char ch=gc(); 
	while(!isdigit(ch))ch=gc();
	while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
	return ans;
}
const int N=2e6+5;
ll n,k,lim,tot,ans,f1[N],f2[N];
int pri[N];
inline void init(ll x){
	lim=sqrt(x),tot=0;
	if(x<=1)return;
	for(ri i=1;i<=lim;++i)f1[i]=i-1,f2[i]=x/i-1;
	ll t;
	for(ri p=1;p<=lim;++p){
		if(f1[p]==f1[p-1])continue;
		pri[++tot]=p,t=f1[p-1];
		for(ri i=1;i<=lim/p;++i)f2[i]-=f2[i*p]-t;
		for(ri i=lim/p+1,up=min((ll)lim,n/(ll)p/(ll)p);i<=up;++i)f2[i]-=f1[x/i/p]-t;
		if(lim>=(ll)p*p)for(ri i=lim,up=p*p;i>=up;--i)f1[i]-=f1[i/p]-t;
	}
}
inline void solve(int pos,ll pre,ll up){
	ll t=up<=lim?f1[up]:f2[n/up];
	//统计一坨f(x)的贡献,其中f(x)的最大质因子为1且之前质因子的贡献为pre
	ans+=(k+1)*pre*(t-f1[pri[pos-1]]);
	for(ri i=pos;i<=tot;++i){
		if(up<(ll)pri[i]*pri[i])return;
		for(ll mult=pri[i],tim=1;mult<=up;mult*=pri[i],++tim){//枚举质数幂次统计答案
			if(mult*pri[i]<up)solve(i+1,pre*(k*tim+1),up/mult);//看之后能不能更大质因子
			if(tim>=2)ans+=pre*(k*tim+1);//计算f(x)的最大质因子不为1的贡献
		}
	}
}
int main(){
	for(ri tt=read();tt;--tt){
		n=read(),k=read(),ans=1;
		init(n),solve(1,1,n);
		cout<<ans<<'\n';
	}
	return 0;
}

e . g . 4 e.g.4 f ( i ) f(i) 的前缀和, f ( i ) f(i) 满足:
f ( 1 ) = 1 f(1)=1
f ( p c ) = p   x o r   c , p p r i m e f(p^c)=p\ xor\ c,p\in prime
f ( a b ) = f ( a ) f ( b ) , g c d ( a , b ) = 1 f(ab)=f(a)f(b),gcd(a,b)=1
跟上一道题差不多,预处理时要计算出质数异或1的前缀和。
可以自己手推一下。
代码:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int mod=1e9+7,N=2e6+5,inv2=5e8+4;
typedef long long ll;
inline int add(const int&a,const int&b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(const int&a,const int&b){return a>=b?a-b:a-b+mod;}
inline int mul(const int&a,const int&b){return (ll)a*b%mod;}
inline int ksm(int a,int p){int ret=1;for(;p;p>>=1,a=mul(a,a))if(p&1)ret=mul(ret,a);return ret;}
inline void Add(int&a,const int&b){a=a+b>=mod?a+b-mod:a+b;}
inline void Dec(int&a,const int&b){a=a>=b?a-b:a-b+mod;}
inline void Mul(int&a,const int&b){a=(ll)a*b%mod;}
ll n,lim;
int f1[N],f2[N],s1[N],s2[N],pri[N],tot=0,ans;
inline int S(const int&x){return mul(mul(x,x+1),inv2);}
inline void init(ll x){
	lim=sqrt(x),tot=0;
	if(x<=1)return;
	for(ri i=1;i<=lim;++i)f1[i]=i-1,f2[i]=dec(x/i%mod,1),s1[i]=dec(S(i),1),s2[i]=dec(S(x/i%mod),1);
	for(ri tf,ts,p=1;p<=lim;++p){
		if(f1[p]==f1[p-1])continue;
		pri[++tot]=p,tf=f1[p-1],ts=s1[p-1];
		for(ri i=1;i<=lim/p;++i){
			Dec(f2[i],dec(f2[i*p],tf));
			Dec(s2[i],mul(dec(s2[i*p],ts),p));
		} 
		for(ri i=lim/p+1,up=min(lim,x/(ll)p/(ll)p);i<=up;++i){
			Dec(f2[i],dec(f1[x/i/p],tf));
			Dec(s2[i],mul(dec(s1[x/i/p],ts),p));
		}
		if(lim>=(ll)p*p)for(ri i=lim,up=p*p;i>=up;--i){
			Dec(f1[i],dec(f1[i/p],tf));
			Dec(s1[i],mul(dec(s1[i/p],ts),p));
		}
	}
	for(ri i=1;i<=lim;++i){
		Dec(s1[i],f1[i]);
		if(i>=2)Add(s1[i],2);
		Dec(s2[i],f2[i]);
		if(n/i>=2)Add(s2[i],2);
	}
}
inline void solve(int pos,int pre,ll up){
	int t=up<=lim?s1[up]:s2[n/up];
	Add(ans,mul(pre,dec(t,s1[pri[pos-1]])));
	for(ri i=pos;i<=tot;++i){
		if(up<(ll)pri[i]*pri[i])return;
		for(ll mult=pri[i],tim=1;mult<=up;mult*=pri[i],++tim){
			if(mult*pri[i]<up)solve(i+1,mul(pre,pri[i]^tim),up/mult);
			if(tim>=2)Add(ans,mul(pre,pri[i]^tim));
		}
	}
} 
int main(){
	cin>>n,ans=1;
	init(n),solve(1,1,n);
	cout<<ans;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/dreaming__ldx/article/details/91354726
今日推荐