欧拉函数、欧拉定理、费马小定理、拓展欧拉定理

欧拉函数、欧拉定理、费马小定理、拓展欧拉定理

(1.) 欧拉函数

(1.1) 定义

定义不超过 (m) 且与 (m) 互质的正整数个数(phi(m)) ,这个函数称为欧拉函数

例如, (phi(1)=1, phi(3)=2, phi(10)=4)

(1.2) 表达式及其证明

[phi(m)=mprod_{i=1}^{n}(1-frac{1}{p_{i}}) ]

其中 (p_{i})(m) 的质因子,下面证明这个表达式。

(1))(m) 为素数,则

[phi(m)=m-1=m(1-frac{1}{m}) ]

(2))(m) 为素数幂。即 (m=p^{k}) ,其中 (p) 为素数。考虑所有不大于 (m) 且与 (m) 不互质的正整数,他们可以被列举出来,即 (1cdot p, 2cdot p, 3cdot p, ... p^{k -1}cdot p),共计 (p^{k-1}) 个数,所以

[phi(m)=phi(p^{k}) = p^{k}-p^{k-1}=p^{alpha}(1-frac{1}{p}) ]

(3))(m) 为合数,那么

[m=p_{1}^{k_{1}}cdot p_{2}^{k_{2}}cdot ... p_{n}^{k_{n}} ]

由于欧拉函数是积性函数,又 (p_{i}^{k_{i}}) 两两互质,所以

[phi(m)=prod_{i=1}^{n}phi(p_{i}^{k_{i}}) ]

[phi(m)=prod_{i=1}^{n}p_{i}^{k_{i}}(1-frac{1}{p_{i}}) ]

[phi(m)=mprod_{i=1}^{n}(1-frac{1}{p_{i}}) ]

至此,表达式推导完毕

(1.3) 欧拉函数 (code)

(1.3.1) 求单个数的欧拉函数

根据

[phi(m)=mprod_{i=1}^{n}(1-frac{1}{p_{i}}) ]

计算

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

(1.3.2) 线性筛一个范围内的欧拉函数

我们知道,在欧拉筛中,合数 (n) 被其最小的质因子 (p) 筛去

(n = n'cdot p)

(pmid n'),则 (n') 含有 (n) 的所有质因子

所以

[phi(n) = pcdot n'cdot prod_{i=1}^{n}(1-frac{1}{p_{i}}) = pcdot phi(n') ]

(p mid n'),则 ((p, n') = 1),由积性函数性质得到

[phi(n) = phi(p)cdot phi(n') = (p - 1)cdot phi(n') ]

int n, prime[N], phi[N], vis[N];
int Euler_sieve()
{
    int cnt = 0;//length of prime table
    for(int i = 2; i <= n; ++i)
        vis[i] = 1;
    for(int i = 2; i <= n; ++i){
        if(vis[i]) prime[++cnt] = i, phi[i] = i - 1;//素数的欧拉函数值为 i - 1
        for(int j = 1; j <= cnt && prime[j] * i <= n; ++j){
            vis[prime[j] * i] = 0;
            phi[prime[j] * i] = phi[i] * (prime[j] - 1);
            if(i % prime[j] == 0) {
                phi[prime[j] * i] = prime[j] * phi[i];
                break;
            }
        }
    }
    return cnt;
}

(2.) 欧拉定理

((a, m)=1) ,则 (a^{phi(m)}equiv 1 (mod m))

下证欧拉定理

设模 (m) 的一个简化剩余系 (P_{1}),其中的元素为

[p_{i}, i = 1, 2, ... , phi(m) - 1 ]

我们知道

[ap_{i}, i = 1, 2, ... , phi(m) - 1 ]

也构成模 (m) 的一个简化剩余系

所以

[prod_{i=1}^{phi(m)}ap_{i}equiv prod_{i=1}^{phi(m)}p_{i} (mod m) ]

[(a^{phi(m)}-1)prod_{i=1}^{phi(m)}p_{i}equiv 0 (mod m) ]

由于 (p_{i})(m) 互质,所以

[(p_{i}, m) = 1 ]

所以

[(prod_{i=1}^{phi(m)}p_{i}, m) = 1 ]

所以

[a^{phi(m)}-1equiv 0 (mod m) ]

[a^{phi(m)}equiv 1 (mod m) ]

至此,定理证明完毕

(3.) 费马小定理

((a, m)=1) ,则 (a^{m-1}equiv 1 (mod m))

费马小定理其实是欧拉定理的一种特殊情况,即模数 (m) 是素数时的情况

证明了欧拉定理,也就证明了费马小定理

(4.) 拓展欧拉定理

对于 (a, b, m),若满足

[bgeq phi(m), (a, m) eq 1 ]

[a^{b}equiv a^{b mod phi(m) + phi(m)} (mod m) ]


先证明三个引理

(1.)(m_{1}, m_{2}, ... , m_{k}) 互质,则由 (xequiv y (mod m_{i}), i = 1, 2, ...\, k),可以推出 (xequiv y (mod m_{1}m_{2}...m_{k}))

(2.)((a, m)=1),则 (a^{b}equiv a^{b mod phi(m)} (mod m))

(3). 对于素数幂 (p^{k}),满足 (phi(p^{k})geq k, kin mathbb{N})


先证明引理 (1)

(m_{1}, m_{2}, ... , m_{k}) 互质

[(m_{1}, m_{2}, ... , m_{k}) = 1 ]

[[m_{1}, m_{2}, ... , m_{k}] = m_{1}m_{2}...m_{k} ]

[xequiv y (mod m_{i}), i = 1, 2, ...\, k ]

知道 (x - y)(m_{1}, m_{2}, ... , m_{k}) 的公倍数

所以

[[m_{1}, m_{2}, ... , m_{k}]mid x - y ]

所以

[xequiv y (mod m_{1}m_{2}...m_{k}) ]

(Q.E.D)


下证引理 (2)

[a^{b}=a^{b-b mod phi(m)+b mod phi(m)} ]

[a^{b}=a^{b-b mod phi(m)}cdot a^{b mod phi(m)} ]

要证明引理 (2),即证明

[a^{b-b mod phi(m)}cdot a^{b mod phi(m)}equiv a^{b mod phi(m)} (mod m) ]

由于

[(a, m) = 1 ]

所以

[(a^{b mod phi(m)}, m) = 1 ]

所以转化为证明

[a^{b-b mod phi(m)}equiv 1 (mod m) ]

由于

[phi(m)mid b-b mod phi(m) ]

[b-b mod phi(m) = qcdot phi(m), qin mathbb{Z} ]

结合欧拉定理

[a^{phi(m)}equiv 1 (mod m) ]

由同余性质,将 (q) 个上式相乘即可得到要证明的式子

(Q.E.D.)


下证引理 (3)

[phi(p^{k}) = p^{k} - p^{k - 1} = p^{k - 1}(p - 1) ]

要证明

[phi(p^{k})geq k, kin mathbb{N} ]

即证明

[p^{k - 1}(p - 1)geq k, kin mathbb{N} ]

由于 (p -1geq 1),故考虑证明

[p^{k - 1}geq k, kin mathbb{N} ]

由于 (p) 是素数,对 (p) 进行放缩,有 (pgeq 2)

考虑证明 (2^{k - 1}geq k, kin mathbb{N})

构造数列

[f(k) = 2^{k - 1} - k, kin mathbb{N} ]

[f(k + 1) - f(k) = 2^{k - 1} - 1 ]

(kgeq 1) 时,(f(k + 1) - f(k)geq 0),所以此时数列递增

取最小值,得到

[f(k)geq f(1) = 0 ]

所以

[2^{k - 1}geq k, kgeq 1 ]

特判 (k = 0)

[2^{0 - 1} = frac{1}{2}geq 0 ]

所以

[2^{k - 1}geq k, kin mathbb{N} ]

所以

[phi(p^{k}) = p^{k - 1}(p - 1)geq p^{k - 1}geq 2^{k - 1}geq k, kin mathbb{N} ]

所以

[phi(p^{k})geq k, kin mathbb{N} ]

(Q.E.D.)


下证拓展欧拉定理

(m) 分解,即

[m = p_{1}^{k_{1}}cdot p_{2}^{k_{2}}cdot ... cdot p_{n}^{k_{n}} ]

由引理 (1) 知道,若对于每一个 (p_{i})

都有

[a^{b}equiv a^{b mod phi(p_{i}^{k_{i}}) + phi(p_{i}^{k_{i}})} (mod p_{i}^{k_{i}}) ]

则待证命题成立

分类讨论 ((a, p_{i}^{k_{i}}))

[(a, p_{i}^{k_{i}}) = 1 ]

[a^{phi(p_{i}^{k_{i}})}equiv 1 (mod p_{i}^{k_{i}}) ]

所以

[a^{b mod phi(p_{i}^{k_{i}}) + phi(p_{i}^{k_{i}})}equiv a^{b mod phi(p_{i}^{k_{i}})} (mod p_{i}^{k_{i}}) ]

由引理 (2) 知道

[a^{b}equiv a^{b mod phi(p_{i}^{k_{i}})} (mod p_{i}^{k_{i}}) ]

所以

[a^{b}equiv a^{b mod phi(p_{i}^{k_{i}}) + phi(p_{i}^{k_{i}})} (mod p_{i}^{k_{i}}) ]

[(a, p_{i}^{k_{i}}) eq 1 ]

[p_{i}mid a_{i} ]

[a = qcdot p_{i}, qin mathbb{Z} ]

所以

[a^{k_{i}}equiv q^{k_{i}}cdot p_{i}^{k_{i}}equiv 0 (mod p_{i}^{k_{i}}) ]

由于

[p_{i}^{k_{i}}mid m ]

所以

[phi(p_{i}^{k_{i}})mid phi(m) ]

由引理 (3),结合 (bgeq phi(m)),可以得到不等式

[bgeq phi(m)geq phi(p_{i}^{k_{i}})geq k_{i} ]

[a^{b}equiv a^{b - k_{i}}cdot a^{k_{i}}equiv 0 (mod p_{i}^{k_{i}}) ]

[a^{ phi(p_{i}^{k_{i}})}= a^{ phi(p_{i}^{k_{i}})- k_{i}}cdot a^{k_{i}}equiv 0 (mod p_{i}^{k_{i}}) ]

所以

[a^{b}equiv 0 (mod p_{i}^{k_{i}}) ]

[a^{b mod phi(p_{i}^{k_{i}}) + phi(p_{i}^{k_{i}})}equiv a^{b mod phi(p_{i}^{k_{i}})}cdot a^{ phi(p_{i}^{k_{i}})}equiv 0 (mod p_{i}^{k_{i}}) ]

所以

[a^{b}equiv a^{b mod phi(p_{i}^{k_{i}}) + phi(p_{i}^{k_{i}})} (mod p_{i}^{k_{i}}) ]

综合上述讨论得知,对于每一个 (p_{i}) 都有

[a^{b}equiv a^{b mod phi(p_{i}^{k_{i}}) + phi(p_{i}^{k_{i}})} (mod p_{i}^{k_{i}}) ]

所以

[a^{b}equiv a^{b mod phi(m) + phi(m)} (mod m) ]

(Q.E.D.)


综合一下,欧拉定理即为 (a^{b}equiv a^{b mod phi(m) + phi(m)} (mod m))

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int, int>
#define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " 
"[i == r])
typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int inf = 0x3f3f3f3f;
const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
const int MOD = 1e9 + 7;
const int N = 2e7 + 7;
const double PI = acos(-1);
const double EPS = 1e-6;
using namespace std;

inline int read()
{
    char c = getchar();
    int ans = 0, f = 1;
    while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
    while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
    return ans * f;
}

LL qpow(LL a, LL b, LL m)
{
    if(!a) return 0;
    LL ans = 1;
    while(b) {
        if(b & 1) ans *= a, ans %= m;
        a *= a, a %= m, b >>= 1;
    }
    return ans;
}

int phi(int m)
{
    int ans = m;
    for(int i = 2; i * i <= m; ++i) {
        if(m % i == 0) {
            ans -= ans / i;
            while(m % i == 0) m /= i;
        }
    }
    if(m > 1) ans -= ans / m;
    return ans;
}
int main()
{
    int a, m;
    a = read(), m = read();
    int phim = phi(m);
    int b = 0, f = 0;
    for(char ch = getchar(); isdigit(ch); ch = getchar()) {
        b *= 10, b += ch - '0';
        if(b >= phim) f = 1, b %= phim;
    }
    if(f) b += phim; //b < phi(m) 的时候直接快速幂
    printf("%d
", qpow(a, b, m));
    return 0;
}

(5.) 欧拉定理、费马小定理应用

(5.1) 求逆元

((a, m) = 1),同余式

[axequiv 1 (mod m) ]

有唯一解 (xequiv a^{-1} (mod m))(a^{-1})(a) 在模 (m) 意义下的逆元

由欧拉定理

[a^{phi(m)}equiv 1 (mod m) ]

所以

[xequiv a^{-1}equiv a^{phi(m) - 1} (mod m) ]

特殊的,若 (m) 为素数,(phi(m) = m - 1),所以

[xequiv a^{-1}equiv a^{m-2} (mod m) ]

根据快速幂,可以在 (O(logm)) 时间求得 (a^{-1})(m) 是模数)

LL qpow(LL a, LL b, LL m)
{
    if(!a) return 0;
    LL ans = 1;
    while(b) {
        if(b & 1) ans *= a, ans %= m;
        a *= a, a %= m, b >>= 1;
    }
    return ans;
}
LL inv(LL a, LL m)
{
    return qpow(a, m - 2, m);
}

(m) 不是素数,则考虑用拓展欧几里得算法求逆元

int exgcd(int a, int b, int &x, int &y)
{
    if(!b) {x = 1, y = 0; return a;}
    int r = exgcd(b, a % b, y, x);//y的值被修改为x',x的值被修改为y'
    y -= a / b * x;
    return r;
}
int inv(int a, int m)
{
    int x, y, r;
    r = exgcd(a, m, x, y);
    while(x < 0) x += m;
    return x % m;
}

(5.2) 用欧拉定理化简模数

[a^{b}equiv a^{b mod phi(m) + phi(m)} (mod m) ]

举个栗子

多组数据,给定 (p),求 (2^{2^{2^{2^{...}}}} mod p)

(a = 2^{2^{2^{2^{...}}}})

则问题转化为求

[a mod p ]

由欧拉定理

[2^{2^{2^{2^{...}}}}equiv 2^{a mod phi(p) + phi(p)} (mod p) ]

继续求解

[a mod phi(p) ]

结合欧拉定理

[2^{2^{2^{2^{...}}}}equiv 2^{a mod phi(phi(p)) + phi(phi(p))} ]

继续求解

[a mod phi(phi(p)) ]

由此可见,这是一个递归求解,然后回溯的过程

(phi) 的值越来越小,最终变为 (1),此时达到递归终点,返回 (0),然后开始回溯,加上 (phi)...

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int, int>
#define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " 
"[i == r])
typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int inf = 0x3f3f3f3f;
const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
const int MOD = 1e9 + 7;
const int N = 1e7 + 7;
const double PI = acos(-1);
const double EPS = 1e-6;
using namespace std;

inline int read()
{
    char c = getchar();
    int ans = 0, f = 1;
    while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
    while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
    return ans * f;
}

LL qpow(LL a, LL b, LL m)
{
    if(!a) return 0;
    LL ans = 1;
    while(b) {
        if(b & 1) ans *= a, ans %= m;
        a *= a, a %= m, b >>= 1;
    }
    return ans;
}

int n, prime[N], phi[N], vis[N];
int Euler_sieve(int n = N - 7)
{
    phi[1] = 1;
    int cnt = 0;//length of prime table
    for(int i = 2; i <= n; ++i){
        if(!vis[i]) prime[++cnt] = i, phi[i] = i - 1;//素数的欧拉函数值为 i - 1
        for(int j = 1; j <= cnt && prime[j] * i <= n; ++j){
            vis[prime[j] * i] = 1;
            phi[prime[j] * i] = phi[i] * (prime[j] - 1);
            if(i % prime[j] == 0) {
                phi[prime[j] * i] = phi[i] * prime[j];
                break;
            }
        }
    }
    return cnt;
}

int t, p;
int solve(int p)
{
    if(p == 1) return 0;
    return qpow(2, solve(phi[p]) + phi[p], p);
}
int main()
{
    t = read();
    int l = Euler_sieve();
    while(t--) {
        p = read();
        printf("%d
", solve(p));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/ChenyangXu/p/12722574.html