前言
本文没有详细证明,只有简单的性质与应用。
欧拉函数
定义
φ ( n ) \varphi(n) φ(n)表示1~n的正整数中,与n互质的数的个数。
互质:如果两个或两个以上的整数的最大公约数是 1 ,则称它们为互质。
性质
当n为质数的时候
φ ( n ) = n − 1 \varphi(n) = n - 1 φ(n)=n−1
φ ( n k ) = ( n − 1 ) n k − 1 \varphi(n^k) = (n-1)n^{k-1} φ(nk)=(n−1)nk−1
积性函数
当gcd(a,b) = 1时, φ ( a b ) = φ ( a ) φ ( b ) \varphi(ab) = \varphi(a)\varphi(b) φ(ab)=φ(a)φ(b)
推广到,当n为奇数, φ ( 2 n ) = φ ( n ) \varphi(2n) = \varphi(n) φ(2n)=φ(n)
求法
质因数分解定理得
n = ∏ i = 1 s p i a i n = \prod_{i=1}^{s} p_i^{a_i} n=i=1∏spiai
化简得
φ ( n ) = n ∗ ∏ i = 1 s p i − 1 p i \varphi(n) = n* \prod_{i=1}^{s}\frac{p_i-1}{p_i} φ(n)=n∗i=1∏spipi−1
上面的就可以用求质因数来获得单个欧拉函数,如果想要线性求多个,可以用欧拉筛。
实现如下
const int N = 1e5 + 10;
int p[N], vis[N], cnt; //素数,所有数,记录已有素数数
int phi[N]; //欧拉函数
void get_phi(int n){
phi[1] = 1;
for(int i = 2; i <= n; i++){
if(!vis[i]){
p[cnt++] = i; //记素数
phi[i] = i - 1;
}
for(int j = 0; j < cnt; j++){
if(i * prime[j] > n) break;
int m = i * p[j];
vis[m] = 1;
if(i % p[j] == 0){
//i包含p[j]的所有质因子,把phi[m]按欧拉函数求法展开,再用开头的m替换成i*p[j],p[j]提前,i和剩余部分构成phi[i]
phi[m] = p[j] * phi[i];
break;
}else{
//p[j]是质数,如果i不是p[j]的倍数,则必互质
//i和p[j]互质的情况,积性函数phi[i*p[j]] = phi[i] * phi[p[j]],因为p[j]为素数,所以phi[p[j]] = p[j] - 1
phi[m] = (p[j] - 1) * phi[i];
}
}
}
}
欧拉定理
若gcd(a,p) = 1,有 a φ ( p ) = 1 ( m o d p ) a^{\varphi(p)} = 1(mod\ p) aφ(p)=1(mod p)
当p为素数时,就是费马小定理
拓展欧拉定理
a b = a b b < φ ( m ) a^b = a^b\ b < \varphi(m) ab=ab b<φ(m)
a b = a b m o d φ ( m ) + φ ( m ) b > = φ ( m ) a^b = a^{b\ mod\ \varphi(m) + \varphi(m)}\ b >= \varphi(m) ab=ab mod φ(m)+φ(m) b>=φ(m)
应用
https://www.luogu.com.cn/problem/P2398
https://www.luogu.com.cn/problem/P2568
上面两道思路都差不多。
题目形如:求gcd(x, y) = m的可能数
1 <= x,y <= n
推导思路就是,设x = am, y = bm
代入得:gcd(a, b) = 1
1 < = a , b < = ⌊ n m ⌋ 1 <= a,b <= \lfloor\frac{n}{m}\rfloor 1<=a,b<=⌊mn⌋
跑个欧拉函数前缀和,答案就是
2 ∗ ∑ i = 1 ⌊ n m ⌋ φ ( i ) − 1 2*\sum_{i = 1}^{\lfloor\frac{n}{m}\rfloor}\varphi(i) - 1 2∗i=1∑⌊mn⌋φ(i)−1
(1,1)与(1,1)是相同的所以-1,(1,2),(2,1)这样是不同的所以*2