各种筛子

各种筛子

各种筛子

donotctjuntilAFO

·

2023-08-23 08:04:54

·

算法·理论

前言

oi中有一堆筛子,如:埃氏筛、线性筛、杜教筛、powerfulnumber筛、冷群筛、洲阁筛、min25筛、lwx爷爷筛。

正文

埃氏筛

通常用来筛质数,每次用质数的倍数来标记合数,复杂度 O(n\log \log n)。

f(i,2,n)

if(!vis[i])

for(int j=i<<1;j<=n;j+=i)

vis[j]=1;

优化:

我们每次只要筛到 \sqrt n 就足够了。

我们可以只筛奇数。

用 bitset 优化。

代码:

bitset vis;

void init(int n){

for(int j=4;j<=n;j+=2)

vis[j]=1;

for(int i=3;i*i<=n;i+=2)

if(!vis[i])

for(int j=i*i;j<=n;j+=i)

vis[j]=1;

}

此时效率已经比一般的线性筛都要快了。

应用:记录 1\sim n 中的所有数的质因数。

在筛的同时记录即可。

代码:

f(i,2,n)

if(!vis[i]){

prime[i][++cnt[i]]=i;

for(int j=i<<1;j<=n;j+=i)

vis[j]=1,prime[j][++cnt[j]]=i;

}

线性筛

只用每个数的最小质因子标记,这样就只会标记一次,复杂度 O(n)。

代码:

f(i,2,n){

if(!vis[i])

prime[++cnt]=i;

for(int j=1;j<=cnt&&i*prime[j]<=n;++j){

vis[i*prime[j]]=1;

if(!(i%prime[j]))

break;

}

}

应用:如果一个积性函数 f 可以 O(1) 计算 f(p^k) 就可以在 O(n) 内求出函数 1\sim n 的值,如 \varphi,\mu,d,\sigma 。

杜教筛

可以快速算出大部分积性函数(甚至普通函数)的前缀和。

我们要算, S(n)=\displaystyle \sum_{i=1}^{n}f(i)

只要我们找到一个积性函数 g 使得可以快速算出 \displaystyle \sum_{i=1}^{n}(f\ast g)(i) 和 g(i) 。

那么 \displaystyle S(n)=\frac{\sum_{i=1}^{n}(f\ast g)(i)-\sum_{i=2}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor)}{g(1)}

用数论分块求 \displaystyle \sum_{i=2}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor) 即可,复杂度 O(n^{\frac{3}{4}}) 。

如果能用线性筛预处理出 S(1)\sim S(k) 取 k=n^{\frac{2}{3}} 得最优复杂度 O(n^{\frac{2}{3}}) 。

例1 求 \displaystyle \sum_{i=1}^{n}\varphi(i),\sum_{i=1}^{n}\mu(i)

易得 \varphi\ast 1=\mathrm{id},\mu\ast 1=\epsilon .

代码:

#include

#define f(i,l,r) for(int i=l;i<=r;++i)

#define F(i,r,l) for(int i=r;i>=l;--i)

#define int long long

#define ULL unsigned long long

#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)

#define read(n) {int _x=0,_ty=1;char _c=getchar();while(!isdigit(_c)){if(_c=='-')_ty=-1;_c=getchar();}while(isdigit(_c))_x=10*_x+_c-'0',_c=getchar();n=_x*_ty;}

char buf[1<<21],*p1=buf,*p2=buf;

using namespace std;

const int N=3000005;

int T,n,prime[N],cnt,mu[N],phi[N];

bool vis[N];

map sphi,smu;

void init(int n){

mu[1]=phi[1]=1;

f(i,2,n){

if(!vis[i])

prime[++cnt]=i,mu[i]=-1,phi[i]=i-1;

for(int j=1;j<=cnt&&i*prime[j]<=n;++j){

vis[i*prime[j]]=1;

if(i%prime[j])

mu[i*prime[j]]=-mu[i],phi[i*prime[j]]=phi[i]*(prime[j]-1);

else{

phi[i*prime[j]]=phi[i]*prime[j];break;

}

}

}

f(i,1,n)

phi[i]+=phi[i-1],mu[i]+=mu[i-1];

}

int sumphi(int n){

if(n<=3000000)

return phi[n];

if(sphi[n])

return sphi[n];

int ans=(n+1)*n>>1;

for(int l=2,r;l<=n;l=r+1){

r=n/(n/l);

ans-=(r-l+1)*sumphi(n/l);

}

return sphi[n]=ans;

}

int summu(int n){

if(n<=3000000)

return mu[n];

if(smu[n])

return smu[n];

int ans=1;

for(int l=2,r;l<=n;l=r+1){

r=n/(n/l);

ans-=(r-l+1)*summu(n/l);

}

return smu[n]=ans;

}

signed main(){

read(T);

init(3000000);

while(T--){

read(n);

printf("%lld %lld\n",sumphi(n),summu(n));

}

return 0;

}

相关推荐

365bet亚洲体育 1998年国际足联世界杯

1998年国际足联世界杯

365bet官网网址是多少 台式电脑键盘怎么插口在哪

台式电脑键盘怎么插口在哪

bst365大陆投注 dnf封装备多少蜜蜡,100级传说封装要多少蜜蜡

dnf封装备多少蜜蜡,100级传说封装要多少蜜蜡