积性函数线性筛

OI中有时需要我们线性筛某些函数,我们筛的主要是积性函数

1st:线性筛素数

#include<iostream>
#include<cstdio>
using namespace std;
const int MAXN=1e4+5;
int N,prime[MAXN],vis[MAXN],tot;
void get_prime(int N){
	vis[1]=1;
	for(int i=2;i<=N;i++){
		if(!vis[i]) prime[++tot]=i;
		for(int j=1;j<=tot&&i*prime[j]<=N;j++){
			vis[i*prime[j]]=1;
			if(!(i%prime[j])) break;
		}
	}
}
int main(){
	get_prime(1e3);
	for(int i=1;i<=tot;i++)
		printf("%d ",prime[i]);
	return 0;
}

2nd:欧拉函数线性筛:

#include<iostream>
#include<cstdio>
using namespace std;
const int MAXN=1e4+5;
int n,prime[MAXN],vis[MAXN],phi[MAXN],tot;
void get_phi(int n){
	vis[1]=phi[1]=1;
	for(int i=2;i<=n;i++){
		if(!vis[i]) prime[++tot]=i,phi[i]=i-1;
		for(int j=1;j<=tot&&i*prime[j]<=n;j++){
			vis[i*prime[j]]=1;
			if(!(i%prime[j])){
				phi[i*prime[j]]=phi[i]*prime[j];
				break;
			}
			phi[i*prime[j]]=phi[i]*phi[prime[j]];
		}
	}
}
int main(){
	get_phi(1e3);
	for(int i=1;i<=tot;i++)
		printf("%d ",phi[i]);
	return 0;
}

欧拉函数其他求法:

求单个数的欧拉函数:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 int n;
 7 int phi(int N){
 8     int m=N;
 9     for(int i=2;i*i<=N;++i){
10         if(N%i==0){
11             m=m/i*(i-1);
12             while(N%i==0) N/=i;
13         }
14     }
15     if(N>1) m=m/N*(N-1);
16     return m;
17 }
18 int main(){
19     scanf("%d",&n);
20     printf("%d\n",phi(n));
21     return 0;
22 }
View Code

复杂度略大于线性的求法:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 int n,phi[1000006];
 7 void get_phi(int N){
 8     for(int i=1;i<=N;++i) phi[i]=i;
 9     for(int i=2;i<=N;++i){
10         if(phi[i]==i){
11             for(int j=i;j<=N;j+=i){
12                 phi[j]=phi[j]/i*(i-1);
13             }
14         }
15     }
16 }
17 int main(){
18     scanf("%d",&n);
19     get_phi(n);
20     for(int i=1;i<=n;++i){
21         printf("%d\n",phi[i]);
22     }
23     return 0;
24 }
View Code

欧拉函数一个性质:$\sum\limits_{d|n}\phi(d)=n$

3rd:莫比乌斯函数线性筛(虽然我不知道莫比乌斯函数是什么以及怎么用)

#include<iostream>
#include<cstdio>
using namespace std;
const int MAXN=1e4+5;
int n,prime[MAXN],vis[MAXN],mu[MAXN],tot;
void get_mu(int n){
	vis[1]=mu[1]=1;
	for(int i=2;i<=n;i++){
		if(!vis[i]) prime[++tot]=i,mu[i]=-1;
		for(int j=1;j<=tot&&i*prime[j]<=n;j++){
			vis[i*prime[j]]=1;
			if(!(i%prime[j])){
				mu[i*prime[j]]=0;
				break;
			}
			mu[i*prime[j]]=mu[i]*mu[prime[j]];
			//根据莫比乌斯函数的定义,这里也可以写为
			//mu[i*prime[j]]=-mu[i];
		}
	}
}
int main(){
	get_mu(1e3);
	for(int i=1;i<=tot;i++)
		printf("%d ",mu[i]);
	puts("");
	return 0;
}

4th:线性筛约数个数:

#include<iostream>
#include<cstdio>
using namespace std;
const int MAXN=1e4+5;
int n,prime[MAXN],vis[MAXN],d[MAXN],tot,a[MAXN];
void get_d(int n){
	vis[1]=d[1]=a[1]=1;
	for(int i=2;i<=n;i++){
		if(!vis[i]) prime[++tot]=i,d[i]=2,a[i]=1;
		for(int j=1;j<=tot&&i*prime[j]<=n;j++){
			vis[i*prime[j]]=1;
			if(!(i%prime[j])){
				d[i*prime[j]]=d[i]/(a[i]+1)*(a[i]+2);
                a[i*prime[j]]=a[i]+1;
				break;
			}
			d[i*prime[j]]=d[i]*d[prime[j]];
            a[i*prime[j]]=1;
		}
	}
}
int main(){
	get_d(1e3);
	for(int i=1;i<=tot;i++)
		printf("%d ",d[i]);
	puts("");
	return 0;
}

5th:线性筛约数和:

#include<iostream>
#include<cstdio>
using namespace std;
const int MAXN=1e4+10;
int N,prime[MAXN],vis[MAXN],SD[MAXN],sum[MAXN],low[MAXN],tot;
void GetSumD(int N){
    vis[1]=SD[1]=low[1]=sum[1]=1;
    for(int i=2;i<=N;i++){
        if(!vis[i]) prime[++tot]=i,sum[i]=SD[i]=i+1,low[i]=i;
        for(int j=1;j<=tot&&i*prime[j]<=N;j++){
            vis[i * prime[j]]=1;
            if(!(i%prime[j])){
                low[i*prime[j]]=low[i]*prime[j];
                sum[i*prime[j]]=sum[i]+low[i*prime[j]];
                SD[i*prime[j]]=SD[i]/sum[i]*sum[i*prime[j]];
                break;
            }
            low[i*prime[j]]=prime[j];
            sum[i*prime[j]]=prime[j]+1;
            //这里low和sum不是积性函数 
            SD[i*prime[j]]=SD[i]*SD[prime[j]];
        }
    }
}
int main() {
    GetSumD(1e3);
    for(int i=1;i<=tot;i++)
        printf("%d ",SD[i]);
	puts("")
    return 0;
}

6th:其他积性函数?卷积?不会了。。。

伪代码:

vis[1] = low[1] = 1; H[1] = 初始化 
for(int i = 2; i <= N; i++) {
    if(!vis[i]) prime[++tot] = i, mu[i] = -1, H[i] = 质数的情况, low[i] = i;
    for(int j = 1; j <= tot && i * prime[j] <= N; j++) {
        vis[i * prime[j]] = 1;
        if(!(i % prime[j])) {
            low[i * prime[j]] = (low[i] * prime[j]); 
            if(low[i] == i) H[i * prime[j]] = 特殊判断;
            else H[i * prime[j]] = H[i / low[i]] * H[prime[j] * low[i]];
            break;
        } 
        H[i * prime[j]] = H[i] * H[prime[j]];
        low[i * prime[j]] = prime[j];
    }
}

 

posted @ 2019-08-15 16:12  xukl21  阅读(204)  评论(0编辑  收藏  举报