1. 程式人生 > >模板(線性時間求1~n的所有歐拉函數值)

模板(線性時間求1~n的所有歐拉函數值)

namespace 別人 mat 假設 name www tle http scan

定理:

(以下p均為質數)

1. φ(p)=p-1

3. 如果 i mod p ≠ 0 那麽 φ(i*p)=φ(i)*φ(p)

2. 如果 i mod p = 0 那麽 φ(i*p)=φ(i)*p

證明(其實只要知道結論就好了,證明可以跳過):


1. 因為p是質數,所以1~p的所有數除了p其他均與p互質

2. 因為 i mod p ≠ 0 且 p為質數,那麽 i 與 p 一定互質,由歐拉函數的積性可得 φ(i*p)=φ(i)*φ(p)

  關於歐拉函數積性的證明(自己口胡的,具體證明還是看別人的博客吧):

    在1~i*p-1的所有數中只有那些既與 i 互質(小於 i 的數有φ(i)個),又與 p 互質(小於 p 的數有φ(p)個)的數才與 i*p 互質

    顯然每個與 i 互質的數(小於 i)乘上任意一個與 p 互質的數(小於 p)都一定與既與 i 互質又與 p 互質,

    一共有φ(i)*φ(p)個數,而且任意一個既與 i 互質又與 p 互質的數一定可以寫成 一個與 i 互質的數和一個與 p 互質的數的乘積

3. 設b=gcd(i,p)

因為p,i不互質,所以 p=k1b,i=k2b

因為 p+i = (k1+k2)b ,所以p+i 與 i 不互質,所以對於任意一個 i ,只要 p 與 i 不互質

那麽 p+i 與 i 不互質,又因為p 與 i 不互質,所以 p+i 與 p 不互質(p+i 與 p 有公因子 b)

所以在 p+1~p+p 的閉區間裏與 p 不互質的數也有 i - φ(p) 個,

同理2p+1~2p+p也有 i - φ(p) 個....

所以1~i*p 的區間中有 i*p - i*φ(p) 個數與 p 不互質(即與p互質的數有 i*φ(p)個)

反過來,如果一個數 i (i<p) 與 p 互質,那麽 p+i 也與 p 互質

假設 p+i 與 p 不互質

那麽設 b=gcd(p+i,p),p+i=k1b,p=k2b,那麽 i = p+i-p=k1b-k2b=(k1-k2)b 與 i p 互質的條件矛盾(有公因子b)

證明完畢。


有了這些條件,我們在用歐拉篩篩質數時就可以一起求出所有數的歐拉函數值了

實現看代碼:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int N=1e5+7;
int n;
int pri[N],cnt,phi[N]//phi存歐拉函數值,其他的就是線性篩的東西了;
bool not_pri[N];
void get_phi()
{
    scanf("%d",&n);
    not_pri[1]=phi[1]=1;
    for(int i=2;i<=n;i++)
    {
        if(!not_pri[i]) { pri[++cnt]=i; phi[i]=i-1; }//如果i是質數,phi[i]=i-1  1.
        for(int j=1;j<=cnt;j++)
        {
            int g=i*pri[j];
            if(g>n) break;
            not_pri[g]=1;
            if(!(i%pri[j])) { phi[g]=phi[i]*pri[j]; break; }//如果i mod p == 0 ,phi[i*p]=phi[i]*p  3.
            phi[g]=phi[i]*phi[pri[j]];//如果 i mod p !=0,phi[i*p]=phi[i]*phi[p]  2.
        }
    }
}

模板(線性時間求1~n的所有歐拉函數值)