3、欧拉函数
1、定义:
1~n 中与 n 互质的数的个数
例如:6 的有 1 2 3 4 5 6 其中,与 n 互质 的 数的个数为 2个分别是:1、5
2、计算:
$ N = p_1^{a1} × p_2^{a2} × p_3^{a3} × … × p_k^{ak} $(例如:6 = 21 × 31)
$ \phi(N) = N(1 - \frac{1}{p_1})(1 - \frac{1}{p_2}) …(1 - \frac{1}{p_k}) $
import java.util.*;public class Main {static int[] vs = new int[10010];public static void main(String[] args) {Scanner sc = new Scanner(System.in);int t = 1;while(t-- > 0) {int n = 6;int ans = n;for(int i = 2;i <= n / i;i++) {if(n % i == 0) {ans = ans / i * (i - 1);while(n % i == 0) n /= i;}}if(n > 1) ans = ans / n * (n-1);System.out.println(ans);}sc.close();}
}
import java.util.*;
public class Main{static int N = 1000010;static int index = 0;static int[] p = new int[N];static boolean[] st = new boolean[N];static int[] phi = new int[N];public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();phi[1] = 1;for(int i = 2;i <= n;i++) {if(!st[i]) {phi[i] = i - 1;p[index++] = i;}for(int j = 0;p[j] <= n / i;j++) {st[p[j] * i] = true;if(i % p[j] == 0) {phi[p[j] * i] = phi[i] * p[j];break;}phi[p[j] * i] = phi[i] * (p[j] - 1);}}long ans = 0;for(int i = 1;i <= n;i++) {ans += phi[i];}System.out.println(ans);sc.close();}
}
3、拓展
对于 1~m 中,与 n 互质的数的个数的 特殊情况
- 如果 n 为质数:直接计算,结果为:$ m - [\frac{m}{n}](表示向向下取整,即为:(int)(m/n)) $
- 如果 m 是 n 的倍数,即:$ m=k \cdot n ,结果为: ,结果为: ,结果为: k \cdot \phi(n) (其中\phi(n)是n的欧拉数) $
- 如果 m 是 n 的次方倍,即:$ m = n^k ,结果为: ,结果为: ,结果为: m=n^{k-1} \cdot n ==> 结果为:n^{k-1} \phi(n) $
用处:如果 a 与 b 互质,那末有:$ \bbox[5px,border:2px solid greenyellow]
{
a^{\phi(b)} \equiv 1 \pmod{b} ===> a^{\phi(b)} - mod - b = 1
}
$
4、快速幂
1、原理
对于一个数 $ a^k 必定可以拆成 必定可以拆成 必定可以拆成 a^{x_1} * a^{x_2} * … * a^{x_k} , 因为: k 必定能转化为二进制,而二进制的有 1 的一项,即为 x < s u b > k < / s u b > ,因此,可以计算每一项的 ,因为:k 必定能转化为二进制,而二进制的有1的一项,即为x<sub>k</sub>,因此,可以计算每一项的 ,因为:k必定能转化为二进制,而二进制的有1的一项,即为x<sub>k</sub>,因此,可以计算每一项的 a^x $进行计算。
因此要预处理计算出:$ a{20}、a{21}、a{22}…a{2k} , 之后,将 ,之后,将 ,之后,将 a^k $分解,计算。
import java.util.*;
public class Main{public static void main(String[] args) {Scanner sc = new Scanner(System.in);long n = 1;while(n-- > 0) {long a = 27; // 底数long k = 36; // 指数long p = (long) (1e9 + 7); // 取模System.out.println(qmi(a,k,p));}sc.close();}static long qmi(long a,long k,long p){long res = 1; // 初始值为 1while(k != 0) {// 如果 k(指数)的末尾为 1,那末直接计算// res = a^x_1 * .. * a^x_kif((k & 1) == 1) res = res * a % p;k >>= 1; // 指数向右移动一位a = a * a % p; // 持续计算预处理}return res; // 返回的就是 a^k % p 的结果}
}
2、费马定理
$ b^{p-1} \equiv 1 \pmod{p} $ 条件:p 与 b 必须互质,也可也是,p 是质数
因此:由此可知,求 b 的模 p 的逆元,即为:$ b^{p-2} $即为 b 模 p 的逆元
public class Main {public static void main(String[] args) {// 求 n! 模 1e9 + 7 的逆元int n = 3;int mod = 1000000007;long ans = 1;for(int i = 1;i <= n;i++)ans = ans * qmi(i,mod - 2,mod) % mod;System.out.println(ans);}static long qmi(long a,long k,long p){long res = 1;while(k != 0) {if((k & 1) == 1)res = res * a % p;k >>= 1;a = a * a % p;}return res;}
}
5、组合数
1、快速计算 $ C_n^m $的值
1、条件:n <= 20000
2、原理:$ C_n^m = C_{n-1}^m + C_{n-1}^{m-1} $ 类似于动态规划
public class Main {static int[][] c = new int[20010][20010];public static void main(String[] args) {long s = System.currentTimeMillis();int n = 20000;for(int i = 0;i < n;i++) {for(int j = 0;j <= i;j++) {if(j == 0) c[i][j] = 1;else c[i][j] = c[i-1][j] + c[i-1][j-1];}}System.out.println(c[6][2]);System.out.println(System.currentTimeMillis() - s);}
}
6、容斥原理
主要用于计算集合并集的个数,除去相交的个数。
容斥原理:$ S_1 ∪ S_2 ∪ S_3 = S_1 ∩ S_2 ∩ S_3 - (S_1 ∩ S_2) - (S_1 ∩ S_3) - (S_2 ∩ S_3) + (S_1 ∩ S_2 ∩ S_3) $
要求从 1~ n 中任意选择任意个数,那末可以用位运算来遍历这些所有的选择。