1. 程式人生 > 實用技巧 >Euler::尤拉小解(懵)(っ °Д °)っ

Euler::尤拉小解(懵)(っ °Д °)っ

說我會證明那是假的。。。

尤拉函式是個好東西,用φ(n)表示

尤拉函式是求小於等於n的數中與n互質的數的數目


然後。。。。怎麼用哩?(っ•̀ω•́)っ✎⁾⁾


來個例子: 求一個數n的尤拉值(我是這麼叫的),也就是先把n的質因數求出,再用n減掉其質因數和質因數的倍數(≤n)的和就可以了。

也就是說,可以先在1到n-1中找到與n不互質的數,然後把他們減掉

比如,n=a*b(a,b≠0且a,b為素數),那麼直接去掉a,b的倍數就可以了,當然還要加一遍a,b的公倍數(因為重複減了)。

eg:12=2 2 3

2的倍數:2,4,6,8,10,12

3的倍數:3,6,9,12

本來想直接用12 - 12/2 - 12/3

但是6和12重複減了

所以還要把即是2的倍數又是3的倍數的數加回來 (>﹏<)

所以這樣寫12 - 12/2 - 12/3 + 12/(2*3)


這。這。。這。。。不就是容斥嘛。 但容斥有丁點麻煩。。。

so。。。

φ(12) = 12(1 - 1/2)(1 - 1/3) = 12*(1 - 1/2 - 1/3 + 1/6)

φ(30) = 30(1 - 1/2)(1 - 1/3)(1 - 1/5) = 30(1 - 1/2 - 1/3 - 1/5 + 1/6 + 1/10 + 1/15 - 1/30)

拆開新世界!!!


所以,φ(30)就是先求30質因數2,3,5。

然後φ(30)=30 1/2

2/3 * 4/5

順帶一提。。。φ(1)=1。

如下↓

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

但是!!!

複雜度O(√n),嫌棄

埃篩素數

int phi[N];
void Euler() {
    phi[1]=1;
    for(int i=2;i<N;i++) {
        if(!phi[i]) {
            for(int j=i;j<N;j+=i) {
                if(!phi[j]) phi[j]=j;
                phi[j]=phi[j]/i*(i-1);
            }
        }
    }
}
int main() {
    Euler();
}

另一種,比上面更快的方法

需要用到如下性質

p為質數

  1. Euler(p)=p-1 因為質數p除了1以外的因數只有p,故1至p的整數只有p與p不互質

  2. 如果i mod p = 0, 那麼 Euler(i p)=Euler(i) p (我不會證明)

3.若i mod p ≠ 0, 那麼 Euler(i p)=Euler(i) (p-1) (我不會證明)

(所以我說我會證明都是騙人的╮( ̄▽ ̄)╭)


最後說下

a^b%p 不等價 (a%p)^(b%p)%p

因為 a^φ(p)≡1 (mod p)

所以 a^b%p=(a%p)^(b%φ(p))%p

(尤拉函式前提是a和p互質)

如果p是質數 a^b%p=(a%p)^(b%(p-1))%p


這個式子貌似可以擺脫a,p互質的束縛 a^b%p=(a%p)^(φ(p)+b%φ(p))%p