约数、质数、快速幂
此处不做讲解证明;可以当个工具包,开箱即用
注意点:此处方法实现的类型(int
或long
),虽适用于大部分情况,但在实际使用中,还需考虑一下数据范围
给大家一个简单参考(Java
)
int
: − 2 31 ∼ 2 31 − 1 -2^{31} \sim 2^{31} - 1 −231∼231−1约为 1 0 9 10^9 109级别long
: − 2 63 ∼ 2 63 − 1 -2^{63} \sim 2^{63} - 1 −263∼263−1约为 1 0 18 10^{18} 1018级别
约数
最大公约数(gcd)
static int gcd(int a, int b) {
return b != 0 ? gcd(b, a % b): a;
}
输入:
a = 36, b = 24
输出:
12
最小公倍数(lcm)
static int lcm(int a, int b) {
return a * b / gcd(a, b);
}
输入:
a = 36, b = 24
输出:
72
分解约数
试除法
- 若 d ≥ N d \ge \sqrt N d≥N是 N N N的约数,则 N / d ≤ N N / d \le \sqrt N N/d≤N也是 N N N的约数
- 因此,我们只需扫描 d = 1 ∼ N d = 1 \sim \sqrt N d=1∼N;若能整除,则 N / d N / d N/d也是 N N N的约数
时间复杂度: O ( x ) O(\sqrt x) O(x)
static void divide(int x) {
for (int i = 1; i <= x / i; i ++) {
if (x % i == 0) {
System.out.println(i);
if (x / i != i) {
System.out.println(x / i);
}
}
}
}
输入:
x = 100
输出:
1
100
2
50
4
25
5
20
10
质数
质数判断
时间复杂度: O ( x ) O(\sqrt x) O(x)
static boolean isPrime(int x) {
if (x < 2) {
return false;
}
for (int i = 2; i <= x / i; i ++) {
if (x % i == 0) {
return false;
}
}
return true;
}
输入:
x = 23
x = 4
输出:
true
false
筛法求质数
primes
存储的是小于等于 n n n的所有质数,需要注意的是,此处primes
是达不到代码中N
这个级别- 对于一个足够大的整数 N N N,不超过 N N N的质数大约有 N / ln N N / \ln{N} N/lnN个
时间复杂度: O ( n ) O(n) O(n)
static int N = 110;
static int cnt = 0;
static int[] primes = new int[N]; // 此处primes范围是到不了N的,只是开这么多
static boolean[] st = new boolean[N];
// 线性筛法
static void get_primes(int n) {
for (int i = 2; i <= n; i ++) {
if (!st[i]) {
primes[cnt ++] = i;
}
for (int j = 0; primes[j] * i <= n; j ++) {
st[primes[j] * i] = true;
if (i % primes[j] == 0) {
break;
}
}
}
}
// 输出
public static void main(String[] args) {
get_primes(100);
for (int i = 0; i < cnt; i ++) {
System.out.print(primes[i] + " ");
}
}
输入:
n = 100
输出:
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
质数分解
根据算术基本定理,任何一个大于1的正整数都能唯一分解为有限个质数的乘积,可写作:
N
=
p
1
c
1
p
2
c
2
⋯
p
m
c
m
N = p_1^{c_1}p_2^{c_2}\cdots p_m^{c_m}
N=p1c1p2c2⋯pmcm
其中,
c
i
c_i
ci都是正整数,
p
i
p_i
pi都是质数,且满足
p
1
<
p
2
<
⋯
<
p
m
p_1\lt p_2 \lt \cdots \lt p_m
p1<p2<⋯<pm
时间复杂度: O ( n ) O(\sqrt n) O(n)
static void divide_primes(int n) {
for (int i = 2; i <= n / i; i ++) {
if (n % i == 0) {
int c_i = 0;
while (n % i == 0) {
n /= i;
c_i ++;
}
if (c_i > 0) {
int p_i = i;
System.out.printf("p = %d, c = %d\n", p_i, c_i);
}
}
}
if (n > 1) {
System.out.printf("p = %d, c = 1\n", n);
}
}
输入:
n = 1044
输出:
p = 2, c = 2
p = 3, c = 2
p = 29, c = 1
快速幂
-
从位运算的角度进行考虑
-
a = 2 , b = 10 = 101 0 2 a = 2, b = 10 = 1010_2 a=2,b=10=10102,求 a b a^ b ab
-
a b = 2 2 × 2 8 = 4 × 256 = 1024 a^b = 2^2 \times 2^8 = 4 \times 256 = 1024 ab=22×28=4×256=1024
-
用到快速幂的题目一般还会有一个取余的要求,用不到的话将函数最后一个参数去掉即可
-
函数输出: a b m o d M O D a^b \mod{MOD} abmodMOD
时间复杂度: O ( log b ) O(\log{b}) O(logb)
static long qmi(long a, long b, long MOD) {
long res = 1;
while (b > 0) {
if ((b & 1) == 1) {
res = res * a % MOD;
}
a = a * a % MOD;
b >>= 1;
}
return res;
}
输入:
a = 2L, b = 100L, MOD = (long) (1e9 + 7)
输出:
976371285