素数的线性筛 && 欧拉函数

O(n) 筛选素数

#include<bits/stdc++.h>
using namespace std;
const int M = 1e6 + 10 ;

int mindiv[M] ;//每个数的最小质因数
int prim[M] , pnum ;//存素数
bool vis[M] ;

void prim () {
        for (int i = 2 ; i < M ; i ++) {
                if (!vis[i]) {
                        mindiv[i] = i ;
                        prim[ pnum++ ] = i ;
                }
                for (int j = 0 ; j < pnum ; j ++) {
                        if ( i*prim[j] >= M ) break ;
                        vis[ i*prim[j] ] = 1 ;
                        mindiv[i] = prim[j] ;
                        if (i % prim[j] == 0) break ;
                }
        }
}

int main () {
        prim () ;
        return 0 ;
}

  欧拉函数:phi[i] 为<= i 的范围内与i互质的数的数量

  欧拉埃筛,写起来简单,复杂度O(log(log(N)))(zstu 幻神):

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int M = 1e6 + 10 ;

int n, m, T;

int euler[M];

void Euler () {
        for(int i = 0; i < M ; i ++) euler[i] = i;
        for(int i = 2; i < M ; i ++){
                if(euler[i] == i) {
                        for (int j = i; j < M ; j += i) {
                                euler[j] = euler[j] - euler[j]/i;
                        }
                }
        }
}

int main(){
        Euler ();
        int n ;
        while (~ scanf ("%d" , &n)) printf ("%d
" , euler[n]) ;
        return 0;
}

  

欧拉线筛,写起来复杂点,(墨迹了我半天)复杂度O(N):

#include<bits/stdc++.h>
using namespace std;
const int M = 1e6 + 10 ;
int prim[M] , pnum ;
bool vis[M] ;
int phi[M] ;

void Euler () {
        for (int i = 2 ; i < M ; i ++) {
                if (!vis[i])  {
                        prim[ pnum++ ] = i ;
                        phi[i] = i - 1;
                }
                for (int j = 0 ; j < pnum ; j ++) {
                        int x = i * prim[j] ;
                        if (x >= M ) break ;
                        vis[x] = 1 ;
                        if (i % prim[j] == 0) {
                                int y = i , cnt = 0 , z = prim[j] ;
                                while (y % prim[j] == 0) cnt ++ , y /= prim[j] , z *= prim[j] ;
                                if (y == 1) phi[x] = x - x/prim[j] ;
                                else phi[x] = phi[y] * phi[z] ;
                                break ;
                        }
                        else phi[x] = phi[i] * phi[ prim[j] ] ;
                }
        }
}

int main () {
        Euler () ;
        int n ;
        while (~ scanf ("%d" , &n)) printf ("%d
" , phi[n]) ;
        return 0 ;
}

  线性欧拉跟新:

#include<cstdio>
#include<iostream>
using namespace std;
int prime[100005],phi[1000005];
int main(){
        int i,j;
        for(i=2;i<1000002;++i){
                if(!phi[i]){
                        phi[i]=i-1;
                        prime[++prime[0]]=i;
                }
                for(j=1;j<=prime[0]&&(long long)i*prime[j]<1000002;++j)
                        if(i%prime[j])phi[i*prime[j]]=phi[i]*(prime[j]-1);
                        else{
                                phi[i*prime[j]]=phi[i]*prime[j];
                                break;
                        }
        }
        int T,n;
        scanf("%d",&T);
        while(T--){
                scanf("%d",&n);
                printf("%d
",phi[n+1]);
        }
}

  

原文地址:https://www.cnblogs.com/get-an-AC-everyday/p/4747832.html