zoukankan      html  css  js  c++  java
  • 积性函数线性筛

    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
    ",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
    ",phi[i]);
    22     }
    23     return 0;
    24 }
    View Code

    欧拉函数一个性质:$sumlimits_{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];
        }
    }
    
  • 相关阅读:
    【分布式】缓存穿透、缓存雪崩,缓存击穿解决方案
    mongodb常用查询语法
    依据记录总数和每页大小取页数(转)
    SpringBoot普通类中如何获取其他bean例如Service、Dao(转)
    RabbitMQ三种Exchange模式(fanout,direct,topic)的性能比较(转)
    java中job运行时间
    如何查看某个端口被谁占用
    Push to origin/master was rejected (Git提交错误)(转)
    curl网站开发指南
    2012 不宜进入的三个技术点(中)
  • 原文地址:https://www.cnblogs.com/Juve/p/11358625.html
Copyright © 2011-2022 走看看