写在前面
(2021.5.10 quad update) 添加了扩展欧拉定理、部分例题、欧拉群论的证明链接,优化代码模板。
简介
对于任意实数 (n) ,若满足 (gcd(a,n)=1),则有
欧拉函数
定义
欧拉函数 (varphi(n)) 表示在 (1 sim n) 中,于 (n) 互质的数的数量。
已知上述 (a^{varphi(n)} equiv 1 pmod n),若等式两边同除于 (a) ,则有 (a^{varphi(n)-1} equiv cfrac{1}{a} pmod n).
也就是说,在 (pmod n) 意义下,除以 (a) 就相当于乘以 (a^{varphi(n)-1}),而此时的 (varphi(n)) 被称为欧拉函数。
例如:(varphi(6) = 2),(varphi(30)=8)
容斥原理求欧拉函数
容斥原理
应用
已知一个整数 (n),它必然可以分解为 (p_1^{r_1}p_2^{r_2}p_3^{r_3}cdots p_k^{r_k}),其中 (p) 为 (n) 的质因子。
那么对于 (n),其中 (p_1) 及其倍数的因子数量即为 (cfrac{n}{p_1}),(p_2) 及其倍数的因子数量即为 (cfrac{n}{p_2}),(cdots)。
显然,(1 sim n) 中与 (n) 不互质的因子的数量即为 (cfrac{n}{p_1}+cfrac{n}{p_2}+cfrac{n}{p_3}+cdots+cfrac{n}{p_k})。相反,与 (n) 互质的因子的数量即 (varphi(n)) 为 (n - (cfrac{n}{p_1} + cfrac{n}{p_2} + cfrac{n}{p_3} + cdots + cfrac{n}{p_k}) + NUM - cfrac{n}{p_{1}p_{2}p_{3}cdots p_{k}}) 。
其中 (NUM) 为同时是多个因子的倍数的数的数量。
不难得出,
原式可以因式分解
代码
int phi(int n) //求 varphi(n)
{
int res = n;
for (int i = 2; i <= sqrt(n); i++)
if (!(n % i))
{
res = res / i * (i - 1);
while (!(n % i))
n = n / i;
}
if (n > 1)
res = res / n * (n - 1);
return res;
}
注意
当 (gcd(a,n) eq 1) 时,(a) 在 (pmod n) 意义下不存在逆元。
也就是说,当 (a,n) 不满足 (a perp n) 时,(a,n) 无法在 (pmod n) 意义下作除法。
欧拉函数表
大多数情况下,欧拉函数是可以直接拿来用的,所以如果遇到此类题目,需要首先预处理欧拉函数表。
const int _ = 1000010;
int varphi[_], prime[_], num, fac[_];
void Phi()
{
varphi[1] = 1;
for (int i = 2; i <= n - 1; i++)
{
if (!fac[i])
{
prime[++num] = i;
fac[i] = i;
varphi[i] = i - 1;
}
for (int j = 1; j <= num; j++)
if (prime[j] * i > n || prime[j] > fac[i])
break;
else
{
fac[prime[j] * i] = prime[j];
if (prime[j] < fac[i])
varphi[prime[j] * i] = prime[j] * varphi[i] - varphi[i];
else
varphi[prime[j] * i] = prime[j] * varphi[i];
}
varphi[i] += varphi[i - 1];
}
}
附:逆元扩展
已知一个质数 (p) ,一个实数 (n),且 (n<p) ,求 (1 sim n) 在 (pmod p) 意义下的逆元。
首先求出 (n!) 的逆元,则 (n) 的逆元为 ((n-1)!cdot (n!)^{-1}),即 (cfrac{(n-1)!}{n!}=cfrac{1}{n})。
依此类推,将 ((n!)^{-1}) 乘以 (n),可得到 ([(n-1)!]^{-1}) (cdots)
直到推到 (1) 。
时间复杂度 (O(n)) 。
YES!
例题
P2158 [SDOI2008]仪仗队
对于此题,非常显然每个点与原点生成的矩形对角线上的所有点,都只能看到第一个。也就是说,对于任意整点 ((x,y)) ,点 ((lambda x,lambda y)) ,((lambda >1)) 都是看不到的。
那么有
即对于一个点 ((x,y)) ,若其满足 (gcd(x,y) eq 1) 时,这个点必定看不到。
相反,若其满足 (gcd(x,y)=1) ,且它会被遮挡,则一定存在一个 (mu(mu >1)) 使得 ((cfrac{x}{mu},cfrac{y}{mu})) 能被看到。
又因为 (gcd(x,y)=1),所以 (mu) 一定不存在。
那么可以得出一个结论:一个点 ((x,y)) 能被看到,当且仅当 (gcd(x,y)=1) 。
当 (n=1) 时,答案为 (0)。
否则,答案为 (sum limits_{x=0}^{n-1} sum limits_{y=0}^{n-1}[gcd(x, y)=1], n geq 2)。
展开
其中 (n geq 2)。
根据
有
其中 (n geq 2) 。
引入欧拉函数 (varphi(n))
有
其中 (n geq 2)。
综上所述,
/*
Name: P2158 [SDOI2008]仪仗队
Solution: 欧拉函数
By Frather_
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#define int long long
#define InF 0x3f3f3f3f
#define kMax 10e5
#define kMin -10e5
#define kMod 998244353
using namespace std;
/*==================================================快读*/
inline int read()
{
int X = 0, F = 1;
char CH = getchar();
while (CH < '0' || CH > '9')
{
if (CH == '-')
F = -1;
CH = getchar();
}
while (CH >= '0' && CH <= '9')
{
X = (X << 3) + (X << 1) + (CH ^ 48);
CH = getchar();
}
return X * F;
}
/*===============================================定义变量*/
int n;
const int _ = 1000010;
int phi[_], prime[_], num, fac[_];
/*=============================================自定义函数*/
void Phi()
{
phi[1] = 1;
for (int i = 2; i <= n - 1; i++)
{
if (!fac[i])
{
prime[++num] = i;
fac[i] = i;
phi[i] = i - 1;
}
for (int j = 1; j <= num; j++)
if (prime[j] * i > n || prime[j] > fac[i])
break;
else
{
fac[prime[j] * i] = prime[j];
if (prime[j] < fac[i])
phi[prime[j] * i] = prime[j] * phi[i] - phi[i];
else
phi[prime[j] * i] = prime[j] * phi[i];
}
phi[i] += phi[i - 1];
}
}
/*=================================================主函数*/
signed main()
{
n = read();
Phi();
printf("%lld
", n == 1 ? 0 : 2 * phi[n - 1] + 1);
return 0;
}
扩展欧拉定理
我们已知,只有当 (a,n) 满足 (gcd(a,n)=1) 时,欧拉定理才成立,那么若 (a,b) 不互质呢?
定义
对于 (a,n) 若 (gcd(a,n) eq 1) ,时,有
证明
不妨首先考虑一个质因子 (p),令 (n=s cdot p^r ,gcd(s,p)=1) 。
由 (p^{varphi(s)} equiv 1 pmod s) , 又由 (gcd(s,p)=1) ,则有 (varphi(s) mid varphi(n)),即 (p^{varphi(n)} equiv 1 pmod s)。
根据同余式性质,两边同时乘以一个 (p^r)
那么有
其中 (c geq r)
显然, (r leq varphi(n))
因此
其中 (c geq varphi(n))
上式可转化为
其中 (c geq varphi(n)) 。
类似的,可以有
其中 (c geq varphi(n),k>0) 。
由于 (p) 是 (a) 的因子,即 (a = prod p_{i}^{k_{i}}) ,而对于每一个 (p) 都满足上述证明,那么其乘积也必然满足,所以有
其中 (c geq varphi(n)),
证毕。
例题
P5091 【模板】扩展欧拉定理
RT,模板题。
/*
Name: P5091 【模板】扩展欧拉定理
Solution: 扩展欧拉定理
By Frather_
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#define int long long
#define InF 0x3f3f3f3f
#define kMax 10e5
#define kMin -10e5
#define kMod 998244353
using namespace std;
/*==================================================快读*/
inline int read()
{
int X = 0, F = 1;
char CH = getchar();
while (CH < '0' || CH > '9')
{
if (CH == '-')
F = -1;
CH = getchar();
}
while (CH >= '0' && CH <= '9')
{
X = (X << 3) + (X << 1) + (CH ^ 48);
CH = getchar();
}
return X * F;
}
/*===============================================定义变量*/
int a, m, b;
/*=============================================自定义函数*/
inline int read_(int kmod)
{
int X = 0;
bool F = false;
char CH = getchar();
while (CH < '0' || CH > '9')
CH = getchar();
while (CH >= '0' && CH <= '9')
{
X = (X << 3) + (X << 1) + (CH ^ 48);
if (X >= kmod)
F = true;
X %= kmod;
CH = getchar();
}
return X + (F ? kmod : 0);
}
int phi(int n) //求 varphi(n)
{
int res = n;
for (int i = 2; i <= sqrt(n); i++)
if (!(n % i))
{
res = res / i * (i - 1);
while (!(n % i))
n = n / i;
}
if (n > 1)
res = res / n * (n - 1);
return res;
}
int gcd(int a, int b)
{
return b ? gcd(b, a % b) : a;
}
int Qpow(int a, int t, int p)
{
int res = 1;
while (t)
{
if (t & 1)
res = res * a % p;
a = a * a % p;
t >>= 1;
}
return res;
}
/*=================================================主函数*/
signed main()
{
a = read();
m = read();
int t = phi(m);
b = read_(t);
int g = gcd(a, m);
// if (g = 1)
// printf("%lld
", Qpow(a, b % t, m));
// else if (g != 1 && b < t)
printf("%lld
", Qpow(a, b, m));
// else if (g != 1 && b >= t)
// printf("%lld
", Qpow(a, b % t + t, m));
return 0;
}
欧拉定理的群论证明
详情可参见这篇博客。