1. 程式人生 > >尤拉函式及尤拉線性篩

尤拉函式及尤拉線性篩

尤拉函式

尤拉函式

f(n) : 從1 ~ n 中與 n互質的數的個數

ll Euler(ll n){
    ll ans = 1;
    for(int i = 2; i * i <= n; i++){
        if(n % i == 0){
            n /= i;
            ans *= (i - 1);
            while(n % i == 0){
                n /= i;
                ans *= i;
            }
        }
    }
    if(n > 1) ans *= (n-1);
    return ans ;
}

尤拉線性篩

篩素數(時間複雜度要優於埃氏篩法)

 void get_list(){
       for(int i=2;i<=maxn;i++){
             if(!is_not_pr[i]) prime[++tot]=i;
             for(int j=1;j<=tot&&i*prime[j]<=maxn;j++){
                   is_not_pr[i*prime[j]]=1;//合數標為1,同時,prime[j]是合數i*prime[j]的最小素因子
                   if(i%prime[j]==0) break;//即比一個合數大的質數和該合數的乘積可用一個更大的合數和比其小的質數相乘得到
             }
       }
}

篩尤拉函式 + 素數

時間複雜度 O(n)

//尤拉線性篩:線上性時間內篩素數的同時求出所有數的尤拉函式
int tot;
int phi[MAXN];//儲存各個數字的尤拉函式 
int prime[MAXN]; //按順序儲存素數
bool mark[MAXN];//判斷是否是素數
void get_phi(){
    phi[1] = 1;
    for(int i = 2; i <= MAXN; i++){//相當於分解質因數的逆過程
        if(!mark[i]){
            prime[++tot] = i;
            phi[i] = i-1;
        }
        for(int j = 1; j <= tot; j++){
            if(i * prime[j] > N) break;
            mark[i * prime[j]] = 1;//確定i*prime[j]不是素數
            if(i % prime[j] == 0){//判斷prime[j] 是否為 i的約數
                phi[i * prime[j]] = phi[i] * prime[j];
                break;
            }
            else{//prime[j] - 1 就是 phi[prime[j]],利用了尤拉函式的積性
                phi[i * prime[j]] = phi[i] * (prime[j] - 1);
            }
        }
    }
}