- 用欧拉筛法线性筛素数
  \ \ \ \ \ \, 我们知道,若 x x x为素数的话,那么必然若有任意一个不为 1 1 1的数 a a a, ( a ⋅ x ) (a\cdot x) (a⋅x)不是素数,打上标记。
  \ \ \ \ \ \, 并且必然有 a < a ⋅ x a<a\cdot x a<a⋅x, x < a ⋅ x x<a\cdot x x<a⋅x,所以我们不断枚举 a a a,在之前若是没有被打上标记,那么 a a a就是素数。再不断枚举之前筛出来的素数 x x x,对范围 [ a , n ] [a,n] [a,n]中的 ( a ⋅ x ) (a\cdot x) (a⋅x)打上标记。
  \ \ \ \ \ \, 若是当前 a a a已经是某一个 x x x的倍数,那么我们便可不必向后枚举 x x x了,因为后面的 ( a ⋅ x ) (a\cdot x) (a⋅x)一定被打过标记了,这样子可以保证每一个数最多被打过一次标记,复杂度严格 O ( n ) O(n) O(n)。
//prime[0]为素数个数。
bool used[N];
long long prime[N];
long long n,q;
void Get_Prime(long long n){
used[1]=1;
for(long long i=2;i<=n;i++){
if(!used[i])prime[++prime[0]]=i;
for(int j=1;j<=prime[0]&&i*prime[j]<=n;j++){
used[i*prime[j]]=1;
if(i%prime[j]==0)break;
}
}
}
- 用欧拉筛法线性筛欧拉函数 φ \varphi φ,莫比乌斯函数 μ \mu μ
- 筛欧拉函数 φ \varphi φ
  \ \ \ \ \ \, 根据欧拉函数 φ \varphi φ的3条性质:
  1 \ \ \ \ \ \,1 1.若 x x x为素数, φ ( x ) = x − 1 \varphi(x)=x-1 φ(x)=x−1;
  2 \ \ \ \ \ \,2 2.若 x % p = 0 x\%p=0 x%p=0, φ ( x ⋅ p ) = φ ( x ) ⋅ p \varphi(x\cdot p)=\varphi(x)\cdot p φ(x⋅p)=φ(x)⋅p;
  3 \ \ \ \ \ \,3 3.若 x % p ≠ 0 x\%p\neq 0 x%p̸=0,且 p p p为素数, φ ( x ⋅ p ) = φ ( x ) ⋅ ( p − 1 ) \varphi(x\cdot p)=\varphi(x)\cdot (p-1) φ(x⋅p)=φ(x)⋅(p−1);
  \ \ \ \ \ \, 稍微改动一下线性筛素数就好了。
bool vis[N];
int prim[N],phi[N];
void Get_Phi(int n){
phi[1]=1;
for(int i=2;i<=n;i++){
if(!vis[i]){phi[i]=i-1;prim[++prim[0]]=i;}
for(int j=1;j<=prim[0]&&i*prim[j]<=n;j++){
vis[i*prim[j]]=1;
if(i%prim[j]==0){phi[i*prim[j]]=phi[i]*prim[j];break;}
phi[i*prim[j]]=phi[i]*(prim[j]-1);
}
}
}
- 筛莫比乌斯函数 μ \mu μ
  \ \ \ \ \ \, 根据性质,若 x x x为素数, μ ( x ) = − 1 \mu(x)=-1 μ(x)=−1;对于任意数 a a a,存在 μ ( a ⋅ x ) = − μ ( a ) \mu(a\cdot x)=-\mu(a) μ(a⋅x)=−μ(a)。
  \ \ \ \ \ \, 再稍微改动一下线性筛素数就好了。
bool vis[N];
int prim[N],mu[N];
void Get_Mu(int n){
mu[1]=1;
for(int i=2;i<=n;i++){
if(!vis[i]){mu[i]=-1;prim[++prim[0]]=i;}
for(int j=1;j<=prim[0]&&i*prim[j]<=n;j++){
vis[i*prim[j]]=1;
if(i%prim[j]==0)break;
mu[i*prim[j]]=-mu[i];
}
}
}
- 对于任意积性函数 f f f线性筛
  \ \ \ \ \ \, 对于任意积性函数 f f f,我们如何线性筛。
-
如果 p p p是素数: f ( p ) = F 1 ( p ) f(p)=F_1(p) f(p)=F1(p)
-
如果 p p p是素数, i % p ≠ 0 i\%p\neq0 i%p̸=0: f ( p i ) = f ( i ) × F 2 ( p ) f(pi)=f(i)\times F_2(p) f(pi)=f(i)×F2(p)
-
如果 p p p是素数, i % p = 0 i\%p=0 i%p=0:
我们把 p i pi pi 分解成 p c x p^cx pcx ,可以保证 p c p^c pc 与 x x x互质,那么有: f ( p i ) = f ( p c x ) = f ( x ) ∗ F 3 ( p , c ) f(pi)=f(p^cx)=f(x)*F_3(p,c) f(pi)=f(pcx)=f(x)∗F3(p,c)
  \ \ \ \ \ \, 其中,函数 F 1 F_1 F1, F 2 F_2 F2, F 3 F_3 F3需要情况制定,模板如下:
bool vis[N];
int pri[N],cnt[N],power[N];
int prime[N],f[N];
void Get_Shai(int n){
f[1]=1;
for(long long i=1;i<=n;i++)power[i]=1;
for(int i=2;i<=n;i++){
if(!vis[i]){
cnt[i]=1;pri[i]=i;power[i]=i;
prime[++prime[0]]=i;
f[i]=F1(i);
}
for(int j=1,v,pc;j<=prime[0]&&i*prime[j]<=n;j++){
v=i*prime[j];
vis[v]=1;
if(i%prime[j]==0){
cnt[v]=cnt[i]+1;pri[v]=pri[i];power[v]=power[i]*pri[i];
f[v]=f[v/power[v]]*F3(pri[v],cnt[v]);
break;
}
cnt[v]=1;pri[v]=prime[j];power[v]=prime[j];
f[v]=f[i]*F2(prime[j]);
}
}
}
-
模板题:T34163 【模板】线性筛
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cstdio>
#include<vector>
#include<string>
#include<queue>
#include<stack>
#include<cmath>
#include<map>
#include<set>
using namespace std;
const int inf=0x7fffffff;
const double eps=1e-10;
const double pi=acos(-1.0);
//char buf[1<<15],*S=buf,*T=buf;
//char getch(){return S==T&&(T=(S=buf)+fread(buf,1,1<<15,stdin),S==T)?0:*S++;}
inline int read(){
int x=0,f=1;char ch;ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=0;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch&15);ch=getchar();}
if(f)return x;else return -x;
}
const int N=1e7+10;
int Sig(int a){
int ret=0;
for(int i=1;i<=a;i++)if(a%i==0)ret++;
return ret;
}
bool vis[N];
int pri[N],cnt[N],power[N];
int phi[N],mu[N],prime[N],sigma0[N],sigma1[N],inv[N];
void Get_Shai(int n){
phi[1]=mu[1]=sigma0[1]=sigma1[1]=inv[1]=power[1]=1;
for(long long i=2;i<=n;i++)
inv[i]=(n-n/i)*inv[n%i]%n,power[i]=1;
for(int i=2;i<=n;i++){
if(!vis[i]){
cnt[i]=1;pri[i]=i;power[i]=i;
prime[++prime[0]]=i;
phi[i]=i-1;
mu[i]=-1;
sigma0[i]=2;
sigma1[i]=i+1;
}
for(int j=1,v,pc;j<=prime[0]&&i*prime[j]<=n;j++){
v=i*prime[j];
vis[v]=1;
if(i%prime[j]==0){
cnt[v]=cnt[i]+1;pri[v]=pri[i];power[v]=power[i]*pri[i];
phi[v] =phi[i]*prime[j];
sigma0[v]=sigma0[v/power[v]]*(cnt[v]+1);
sigma1[v]=sigma1[v/power[v]]*(power[v]*pri[v]-1)/(pri[v]-1);
break;
}
cnt[v]=1;pri[v]=prime[j];power[v]=prime[j];
phi[v] =phi[i]*(prime[j]-1);
mu[v] =-mu[i];
sigma0[v]=sigma0[i]*2;
sigma1[v]=sigma1[i]*(prime[j]+1);
}
}
}
int main()
{
int n=read();
Get_Shai(n);
for(int i=1;i<=n;i++)printf("%d ",phi[i]);printf("\n");
for(int i=1;i<=n;i++)printf("%d ",mu[i]);printf("\n");
printf("%d ",prime[0]);for(int i=1;i<=prime[0];i++)printf("%d ",prime[i]);printf("\n");
for(int i=1;i<=n;i++)printf("%d ",sigma0[i]);printf("\n");
for(int i=1;i<=n;i++)printf("%d ",sigma1[i]);printf("\n");
for(int i=1;i<=n;i++)printf("%d ",inv[i]);printf("\n");
return 0;
}