欧拉函数、欧拉定理、费马小定理、拓展欧拉定理
欧拉函数、欧拉定理、费马小定理、拓展欧拉定理
\(1.\) 欧拉函数
\(1.1\) 定义
定义不超过 \(m\) 且与 \(m\) 互质的正整数个数为 \(\phi(m)\) ,这个函数称为欧拉函数
例如, \(\phi(1)=1,\ \phi(3)=2,\ \phi(10)=4\)
\(1.2\) 表达式及其证明
其中 \(p_{i}\) 是 \(m\) 的质因子,下面证明这个表达式。
\(1)\) 若 \(m\) 为素数,则
\(2)\) 若 \(m\) 为素数幂。即 \(m=p^{k}\) ,其中 \(p\) 为素数。考虑所有不大于 \(m\) 且与 \(m\) 不互质的正整数,他们可以被列举出来,即 \(1\cdot p,\ 2\cdot p,\ 3\cdot p,\ ...\ p^{k -1}\cdot p\),共计 \(p^{k-1}\) 个数,所以
\(3)\) 若 \(m\) 为合数,那么
由于欧拉函数是积性函数,又 \(p_{i}^{k_{i}}\) 两两互质,所以
即
即
至此,表达式推导完毕
\(1.3\) 欧拉函数 \(code\)
\(1.3.1\) 求单个数的欧拉函数
根据
计算
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\)
若 \(p\mid n'\),则 \(n'\) 含有 \(n\) 的所有质因子
所以
若 \(p\nmid n'\),则 \((p,\ n') = 1\),由积性函数性质得到
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}\),其中的元素为
我们知道
也构成模 \(m\) 的一个简化剩余系
所以
即
由于 \(p_{i}\) 与 \(m\) 互质,所以
所以
所以
即
至此,定理证明完毕
\(3.\) 费马小定理
若 \((a,\ m)=1\) ,则 \(a^{m-1}\equiv 1\ (mod\ m)\)
费马小定理其实是欧拉定理的一种特殊情况,即模数 \(m\) 是素数时的情况
证明了欧拉定理,也就证明了费马小定理
\(4.\) 拓展欧拉定理
对于 \(a,\ b,\ m\),若满足
则
先证明三个引理
\(1.\) 若 \(m_{1},\ m_{2},\ ...\ ,\ m_{k}\) 互质,则由 \(x\equiv y\ (mod\ m_{i}),\ i = 1,\ 2,\ ...\, \ k\),可以推出 \(x\equiv 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,\ k\in \mathbb{N}\)
先证明引理 \(1\)
若 \(m_{1},\ m_{2},\ ...\ ,\ m_{k}\) 互质
则
则
由
知道 \(x - y\) 是 \(m_{1},\ m_{2},\ ...\ ,\ m_{k}\) 的公倍数
所以
所以
\(Q.E.D\)
下证引理 \(2\)
即
要证明引理 \(2\),即证明
由于
所以
所以转化为证明
由于
设
结合欧拉定理
由同余性质,将 \(q\) 个上式相乘即可得到要证明的式子
\(Q.E.D.\)
下证引理 \(3\)
要证明
即证明
由于 \(p -1\geq 1\),故考虑证明
由于 \(p\) 是素数,对 \(p\) 进行放缩,有 \(p\geq 2\)
考虑证明 \(2^{k - 1}\geq k,\ k\in \mathbb{N}\)
构造数列
则
当 \(k\geq 1\) 时,\(f(k + 1) - f(k)\geq 0\),所以此时数列递增
取最小值,得到
所以
特判 \(k = 0\) 时
所以
所以
所以
\(Q.E.D.\)
下证拓展欧拉定理
将 \(m\) 分解,即
由引理 \(1\) 知道,若对于每一个 \(p_{i}\)
都有
则待证命题成立
分类讨论 \((a,\ p_{i}^{k_{i}})\)
若
则
所以
由引理 \(2\) 知道
所以
若
则
设
所以
由于
所以
由引理 \(3\),结合 \(b\geq \phi(m)\),可以得到不等式
而
所以
所以
综合上述讨论得知,对于每一个 \(p_{i}\) 都有
所以
\(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], " \n"[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\n", qpow(a, b, m));
return 0;
}
\(5.\) 欧拉定理、费马小定理应用
\(5.1\) 求逆元
若 \((a,\ m) = 1\),同余式
有唯一解 \(x\equiv a^{-1}\ (mod\ m)\),\(a^{-1}\) 即 \(a\) 在模 \(m\) 意义下的逆元
由欧拉定理
所以
特殊的,若 \(m\) 为素数,\(\phi(m) = m - 1\),所以
根据快速幂,可以在 \(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\) 用欧拉定理化简模数
举个栗子
多组数据,给定 \(p\),求 \(2^{2^{2^{2^{...}}}}\ mod\ p\)
设 \(a = 2^{2^{2^{2^{...}}}}\)
则问题转化为求
由欧拉定理
继续求解
结合欧拉定理
继续求解
由此可见,这是一个递归求解,然后回溯的过程
\(\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], " \n"[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\n", solve(p));
}
return 0;
}

浙公网安备 33010602011771号