【数论】——欧拉函数
定义
- 定义 表示 [1,n] 中与 n 互质的数的个数。 由算术基本定理可得:
- 证明 设 为 n 的质因子,则易知,对于任意 , 其倍数有 : 当 n 有多个质数时,遵循容斥原理,约数个数为:
合并化简后:
欧拉函数的性质及推论(证明结合算术基本定理即可证明)
- 对于x大于1,区间**[1,x]中与n**互质的数的和为:
- 若a,b互质,则有:
求解某数的欧拉函数
分解质因数法
- 由于 表示 [1,n] 中与 n 互质的数的个数,因此只需要对 n 进行质因数分解再带入公式即可求出 。
- 代码
int get_phi(int x)
{
int ans = x;
for (int i = 2; i <= x / i; i++) {if(n%i ==){x = ans / i * (i - 1);// 利用公式(pi-1)/pi
while(x%i == 0)
x /= i;
}
}
if(x>1) // 此时的 x 为 x 的最大质因数
ans = ans / x * (x + 1);
return res;
}
求解区间内所有数的欧拉函数
线性筛法求欧拉函数
- 筛法原理
基于线性筛质数原理(让每一个合数被最小的质数筛去),因此可以用一个递推,从
phi[i],推到,phi[i*primes[j]]。 - 分类讨论:
- 如果 p 是质数,则与 [2,p-1] 所有都互质,即
phi(p) = p-1; - 如果p不是质数:遍历所有质数的倍数,递推见下方代码中注释
- 复杂度分析:
加上
break优化后,为O(n)。 - 代码(注释是重点)
bool st[N];
int primes[N], cnt;
int phi[N];
void get_phis(int x)
{
for (int i = 2; i <= n; i++) {if (!st[i]) {primes[++cnt] = i;
phi[i] = i - 1;// 定义出发,如果 p 是质数,则与 [2,p-1] 所有都互质,即 phi(p) = p-1
}
for (int j = 1; primes[j] <= n / i; j++) {st[primes[j] * i] = true;
if (i % primes[j] == 0 {//primes[j]是 i 的一个质因子
//phi[i]中已经乘了(primes[j]-1)/primes[j]
//phi[primes[j]*i]和 phi[i]的差别在于最前面的 N 上,因此多乘一个 primes[j]保证 N 相同即可
phi[primes[j] * i] = phi[i] * primes[j];
break;
}
// 如果 primes[j]不是 i 的一个质因子,就要多乘一个(primes[j]-1)/primes[j],再乘一个 primes[j]保证 N 相同
// 化简后分母消去,仅剩(primes[j] - 1
phi[primes[j] * i] = phi[i] * (primes[j] - 1);}
}
}