欧拉函数
ϕ ( n ) \phi(n) ϕ(n) 表示 1 ∼ n 1 \sim n 1∼n 中与 n n n 互质的数的个数。
N = p 1 α 1 p 2 α 2 p 3 α 3 . . . p k α k N = p_1^{\alpha_1}p_2^{\alpha_2}p_3^{\alpha_3}...p_k^{\alpha_k} N=p1α1p2α2p3α3...pkαk
ϕ ( n ) = N ( 1 − 1 p 1 ) ( 1 − 1 p 2 ) . . . ( 1 − 1 p k ) \phi(n) = N(1-\frac{1}{p_1})(1-\frac{1}{p_2})...(1-\frac{1}{p_k}) ϕ(n)=N(1−p11)(1−p21)...(1−pk1)
利用容斥原理推导。

有一个实现的细节。 N ∗ ( 1 − 1 n ) = N ∗ ( n − 1 n ) = N / n ∗ ( n − 1 ) N*(1-\frac{1}{n}) = N*(\frac{n-1}{n}) = N/n*(n-1) N∗(1−n1)=N∗(nn−1)=N/n∗(n−1)
#include <iostream>
using namespace std;
int phi(int x){
int res = x;
for (int i = 2; i <= x / i; i ++ )
if (x % i == 0){
res = res / i * (i - 1);
while (x % i == 0) x /= i;
}
if (x > 1) res = res / x * (x - 1);
return res;
}
int main(){
int n;
cin >> n;
while (n -- ){
int x;
cin >> x;
cout << phi(x) << endl;
}
return 0;
}
1. 用公式求N个数的欧拉函数 O ( N k ) O(N \sqrt{k}) O(Nk)
#include<iostream>
using namespace std;
const int N=1e6+10;
int p[N],cnt[N];
long long f(int n){
long long res=n;
for(int i=2;i<=n/i;i++){
if(n%i==0){
res=res/i*(i-1);
while(n%i==0){
n/=i;
}
}
}
if(n>1)
res=res/n*(n-1);
return res;
}
int main(){
int n;cin>>n;
while(n--){
int a;cin>>a;
cout<<f(a)<<endl;;
}
return 0;
}
2.线性筛 1 ∼ n 1\sim n 1∼n 中每一个数的欧拉函数 O ( n ) O(n) O(n)
线性筛可以求很多数论函数
当 i i i 是质数的时候, p h i ( i ) = i − 1 phi(i) = i-1 phi(i)=i−1 。
当 i i i 不是质数的时候:
- 当 i % p r e [ j ] = = 0 i \%pre[j] == 0 i%pre[j]==0 , p r e [ j ] 是 i ∗ p r e [ j ] 的 最 小 质 因 子 pre[j] 是 i*pre[j] 的最小质因子 pre[j]是i∗pre[j]的最小质因子,又因为 i i i 中包含质因子 p r e [ j ] pre[j] pre[j] 。
p h i ( n ) phi(n) phi(n) 只和 n n n 分解出的质数有关,和质数的指数无关,所以 p h i [ i ∗ p r e [ j ] ] = p r e [ j ] ∗ p h i [ i ] phi[i*pre[j]] = pre[j] *phi[i] phi[i∗pre[j]]=pre[j]∗phi[i]。
- 当 i % p r e [ j ] ! = 0 i \%pre[j] !=0 i%pre[j]!=0 , p r e [ j ] pre[j] pre[j] 是比 i ∗ p r e [ j ] i*pre[j] i∗pre[j] 的最小质因子还要小的质因子,所以:
p h i ( i ∗ p r e [ j ] ) = p h i ( i ) ∗ p r e [ j ] ∗ ( 1 − 1 p r e [ j ] ) = p h i [ i ] ∗ ( p r e [ j ] − 1 ) phi(i*pre[j]) = phi(i)*pre[j]*(1-\frac{1}{pre[j]}) = phi[i]*(pre[j]-1) phi(i∗pre[j])=phi(i)∗pre[j]∗(1−pre[j]1)=phi[i]∗(pre[j]−1)
int pre[N],cnt,n;
int phi[N];//求1~n中每个数的欧拉函数
bool st[N];
void get_euler(int n){
phi[1]=1;
for(int i=2;i<=n;i++){
if(!st[i]){
pre[cnt++]=i;
phi[i]=i-1;
}
for(int j=0;pre[j]<=n/i;j++){
st[i*pre[j]]=1;
if(i%pre[j]==0){
phi[i*pre[j]] = pre[j] * phi[i];
break;
}
phi[i*pre[j]] = phi[i] * (pre[j]-1);
}
}
}
欧拉函数的应用
欧拉定理:若 a a a 与 n n n 互质,则 a ϕ ( n ) ≡ 1 ( m o d n ) a^{\phi(n)} \equiv 1 (mod \ n) aϕ(n)≡1(mod n)
剩余系?
证明欧拉定理:
前置知识:a和b互质,c和b互质,a * c和b互质
$1\sim n $ 中 有 p h i ( n ) phi(n) phi(n) 个数和 n n n 互质, a 1 , a 2 , . . . , a p h i ( n ) a_1,a_2,...,a_{phi(n)} a1,a2,...,aphi(n)
所以的 a i a_i ai 乘 a a a 有: a 1 ∗ a , a 2 ∗ a , . . . , a p h i ( n ) ∗ a a_1*a,a_2*a,...,a_{phi(n)}*a a1∗a,a2∗a,...,aphi(n)∗a ,这些数也和 n n n 互质。
又因为这些数两两不同,且与 n n n 互质的个数只有 p h i ( n ) phi(n) phi(n) 个,所以上边的两组是在模 n n n 意义下是相等的。
证明为什么第二组数在模 n n n 的意义下两两不同。
反证:假设 a i , a j a_i,a_j ai,aj 在模 n n n 的意义下是相等的有:
a ∗ a i ≡ a ∗ a j ( m o d n ) a*a_i \equiv a*a_j (mod \ n) a∗ai≡a∗aj(mod n)
a ∗ ( a i − a j ) ≡ 0 ( m o d n ) a*(a_i-a_j) \equiv 0 (mod \ n) a∗(ai−aj)≡0(mod n)
又因为 a a a 和 n n n 是互质的(大条件),所以有 a i − a j ≡ 0 ( m o d n ) a_i-a_j \equiv 0 (mod \ n) ai−aj≡0(mod n) 与1式子矛盾,得证。
#####欧拉定理的特例:费马定理:当 n n n 是质数,且 a a a 与 n n n 互质的时候 a n − 1 ≡ 1 ( m o d n ) a^{n-1} \equiv 1 (mod \ n) an−1≡1(mod n)
两组数的乘积在模 n n n 的意义下是相等的。乘起来化简就证明了欧拉定理。
欧拉定理的推论
若正整数 a a a , n n n 互质,则对于任意正整数 b b b , 有 a b ≡ a b m o d ϕ ( n ) m o d ( n ) a^b \equiv a^{b \ mod \ \phi(n) }\ mod \ (n) ab≡ab mod ϕ(n) mod (n)
蓝书上给出了精简的证明:
b = q ∗ ( ϕ ( n ) ) + r b = q*(\phi(n))+r b=q∗(ϕ(n))+r , 0 ≤ r < ϕ ( n ) 0 \leq r < \phi(n) 0≤r<ϕ(n) ,有:
a b ≡ a q ∗ ( ϕ ( n ) ) + r ≡ a ϕ ( n ) q ∗ a r ≡ 1 q ∗ a r ≡ a r ≡ a b m o d ϕ ( n ) m o d ( n ) a^b \equiv a^{q*(\phi(n))+r} \equiv a^{\phi(n)^{q}}*a^r \equiv 1^q*a^r\equiv a^{r} \equiv a^{b \ mod\ \phi(n)}\ mod \ (n) ab≡aq∗(ϕ(n))+r≡aϕ(n)q∗ar≡1q∗ar≡ar≡ab mod ϕ(n) mod (n)
特别的,如果 a a a 和 n n n 不互质,当 b > ϕ ( n ) b> \phi(n) b>ϕ(n) 时,有 a b ≡ a b m o d ϕ ( n ) + ϕ ( n ) m o d ( n ) a^b \equiv a^{b \ mod\ \phi(n) + \phi(n)} \ mod \ (n) ab≡ab mod ϕ(n)+ϕ(n) mod (n)
逆元
若 b b b, m m m 互质, b ∣ a b|a b∣a, a b ≡ a ∗ x ( m o d n ) \frac{a}{b} \equiv a*x (mod \ n) ba≡a∗x(mod n)
a b ≡ a ∗ b − 1 ( m o d n ) \frac{a}{b} \equiv a*b^{-1} (mod \ n) ba≡a∗b−1(mod n)
x x x 叫做 b b b 模 n n n 的乘法逆元。记作 b − 1 b^{-1} b−1(是个整数)
证明:
发现了盲点! 费马小定理有两种表述方式:
当 n n n 是质数,且 a a a 与 n n n 互质的时候 a n − 1 ≡ 1 ( m o d n ) a^{n-1} \equiv 1 \ (mod \ n) an−1≡1 (mod n)
当 n n n 是质数,则对于任意整数 a a a , 有 a n ≡ a ( m o d n ) a^{n} \equiv a \ (mod \ n) an≡a (mod n)
原理很简单,当 a a a 与 n n n 互质的时候, a % n ! = 0 a\%n!=0 a%n!=0 , 同于式两边就是消去 a a a 了。
利用 费马定理 :
a ∗ x ≡ 1 ( m o d p ) a ∗ x ≡ a p − 1 ( m o d p ) x ≡ a p − 2 ( m o d p ) a*x \equiv 1 (mod\ p)\\ a*x \equiv a^{p-1} (mod \ p)\\ x \equiv a^{p-2} (mod \ p) a∗x≡1(mod p)a∗x≡ap−1(mod p)x≡ap−2(mod p)
无解的情况:如果 a a a 是 p p p 的倍数,那么 p ∣ a ∗ x p|a*x p∣a∗x 有, a ∗ x m o d p = 0 a*x \ mod\ p =0 a∗x mod p=0,原式不成立。
裴蜀定理
对于任意正整数 a , b a,b a,b ,一定存在整数 x , y x,y x,y ,使得: a x + b y = g c d ( a , b ) ax+by = gcd(a,b) ax+by=gcd(a,b)
可以发现 ( a , b ) (a,b) (a,b) 和 a 和 b a和b a和b 能凑出来的最小的正整数。
(a-1)*(b-1)-1 是 a和b 不能凑出来的最大的正整数。
裴蜀定理的证明是通过扩展欧几里得算法得到的。
扩展欧几里得算法
#include<iostream>
#include<algorithm>
using namespace std;
int extgcd(int a,int b,int &x,int &y)// 返回的是gcd(a,b)
{
if(b==0){
// a*x+b*y=gcd(a,b)
// a + 0 = gcd(a,0) = a
x=1,y=0;
return a;
}
/*
递归求解的, b*y+(a%b)*x=gcd(b,a%b)=gcd(a,b)
化简得到
x * a +[y-a/b*x] b = gcd(a,b)
a的系数还是x;
y-=(a/b*x);
*/
int d=extgcd(b,a%b,y,x);//记得翻转 x,y
y-=a/b*x;
return d;
}
int main()
{
int n;cin>>n;
while(n--)
{
int a,b,x,y;
scanf("%d%d",&a,&b);
int t=extgcd(a,b,x,y);
printf("%d %d\n",x,y);
}
return 0;
}
扩展欧几里得的通解。
a x 0 + b y 0 = d x = x 0 − b d k , k ∈ z y = y 0 + a d k ax_0+by_0=d\\ x = x_0-\frac{b}{d}k,k\in z\\ y = y_0+\frac{a}{d}k ax0+by0=dx=x0−dbk,k∈zy=y0+dak
扩欧应用,求解线性同余方程
a x ≡ b ( m o d m ) ax \equiv b \ (mod \ m) ax≡b (mod m)
a x − m y = b ax-my=b ax−my=b , 方程有解的充要条件 g c d ( a , m ) ∣ b gcd(a,m)|b gcd(a,m)∣b
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
int exgcd(int a, int b, int &x, int &y)
{
if (!b){
x = 1, y = 0;
return a;
}
int d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
int main()
{
int n;
scanf("%d", &n);
while (n -- )
{
int a, b, m;
scanf("%d%d%d", &a, &b, &m);
int x, y;
int d = exgcd(a, m, x, y);
if (b % d) puts("impossible");
else printf("%d\n", (LL)b / d * x % m);
}
return 0;
}
在用扩展欧几里得算法求逆元的基础上的 中国剩余定理
设 m 1 , m 2 , . . . , m n m_1,m_2,...,m_n m1,m2,...,mn 是两两互质 的整数, M = ∏ i = 1 n m i M = \prod_{i=1}^{n} m_i M=∏i=1nmi , M i = M m i M_i = \frac{M}{m_i} Mi=miM 。
对于
n
n
n 个整数
a
1
,
a
2
,
.
.
.
,
a
n
a_1,a_2,...,a_n
a1,a2,...,an 方程组。
x
≡
a
1
(
m
o
d
m
1
)
x
≡
a
2
(
m
o
d
m
2
)
.
.
.
x
≡
a
n
(
m
o
d
m
n
)
x \equiv a_1 (mod \ m_1)\\ x \equiv a_2 (mod \ m_2)\\ ...\\ x \equiv a_n (mod \ m_n)
x≡a1(mod m1)x≡a2(mod m2)...x≡an(mod mn)
构造出一组解:
x
=
a
1
∗
M
1
∗
M
1
−
1
+
a
2
∗
M
2
∗
M
2
−
1
+
.
.
.
+
a
n
∗
M
n
∗
M
n
−
1
x = a_1 * M_1*M_1^{-1}+a_2 * M_2*M_2^{-1}+...+a_n * M_n*M_n^{-1}
x=a1∗M1∗M1−1+a2∗M2∗M2−1+...+an∗Mn∗Mn−1 。