基础数论1

质数

试除法判定质数

bool judge(int n) {
	for(int i = 2; i < n; i++) {
		if(n % i == 0) return false;
	}
	return true;
}

时间复杂度: \(O(n)\)

优化

	for(int i = 2; i <= n / i; i++) {
		if(n % i == 0) return false;
	}
	return true;
}

时间复杂度 \(O(n) \Rightarrow O(\sqrt n)\)

试除法分解质因数

void work(int n) {
	for(int i = 2; i <= n / i; i++) {	//n中最多只包含一个大于等于sqrt(n)的质因子
		if(n % i == 0) {		//i一定为质数
			int s = 0;
			while(n % i == 0) {
				n /= i;
				s++;
			}
		}
		cout << i << " " << s << endl;	//i为底数,s为指数
	}
	if(n > 1) cout << n << " " << 1 << endl;	//如果此时n大于1,那么它就是唯一一个大于sqrt(n)的质因子,单独处理
}

时间复杂度: \(O(\sqrt n)\)

筛法

原理:筛去倍数

朴素筛法

void work(void) {
	for(int i = 2; i <= n; i++) {
		if(!st[i]) {
			primes[cnt++] = i;
		}
		for(int j = i + i; j <= n; j += i) st[j] = true;
	}
}

时间复杂度:\(O(n \log n)\)

埃氏筛:只筛去质数的倍数

void work(void) {
	for(int i = 2; i <= n; i++) {
		if(!st[i]) {
			primes[cnt++] = i;
			for(int j = i + i; j <= n; j += i) st[j] = true;
		}
	}
}

时间复杂度:\(O(\log \log n)\)
质数定理:\(1 \sim n\) 中有 \(\frac{n}{\ln n}\) 个质数

线性筛:保证每个合数被最小的质因子筛去

void work(void) {
	for(int i = 2; i <= n; i++) {
		if(!st[i]) primes[cnt++] = i;
		for(int j = 0; primes[j] <= n / i; j++) {
			st[primes[j] * i] = true;
			if(i % primes[j] == 0) break;		//此时primes[j]一定是i的最小质因子
		}
	}
}

正确性证明:

  1. \(i \mod primes[j] = 0\)
    \(primes[j]\)\(i\) 的最小质因子,因此 \(primes[j]\) 一定是 \(primes[j] \times i\) 的最小质因子。
  2. \(i \mod primes[j] \neq 0\)
    \(primes[j]\) 一定小于 \(i\) 的所有质因子,因此 \(primes[j]\) 一定是 \(primes[j] \times i\) 的最小质因子。

约数

试除法求约数

void work(void) {
	vector<int> divisors;
	for(int i = 2; i <= n / i; i++) {
		if(n % i == 0) {
			divisors.push_back(i);
			if(i != n / i) divisors.push_back(n / i);
		}
	}
	sort(divisors.begin(), divisors.end());
}

唯一分解定理

任何一个大于 \(1\) 的整数 \(N\) 一定可以分解成以下形式:

\[N = p_1^{\alpha_1}p_2^{\alpha_2}...p_k^{\alpha_k} \]

其中 \(p_1, p_2, ... , p_k\) 为质数

求约数的个数

\[(\alpha_1 + 1)(\alpha_2 + 1)...(\alpha_k + 1) \]

对于分解出来的每个约数,我们均可再次分解成\(p_1^{\beta_1}p_2^{\beta_2}...p_k^{\beta_k}\)的形式,其中 \(0 \leq \beta_i \leq \alpha_i\) 。选择不同的项可以组成不同的数,对于每个式子,有\(\alpha_i + 1\)中选择(还可以都不选,也就是1),因此约数的个数一共有$ (\alpha_1 + 1)(\alpha_2 + 1)...(\alpha_k + 1) $ 个。

求约数之和

\[(p_1^0 + p_1^1 + ... + p_1^{\alpha_1})...(p_k^0 + p_k^1 + ... + p_k^{\alpha_k}) \]

其实是将所有约数的分解式按分配律整理后的形式。

最大公约数

辗转相除法求最大公约数

\[\gcd(a, b) = \gcd(b, a \mod b) \]

	int gcd(int a, int b) {
		return b ? gcd(b, a % b) : a;
	}
posted @ 2025-04-04 23:23  dbywsc  阅读(53)  评论(0)    收藏  举报