GESP五级一点通(C++)

洛谷原文:GESP五级知识点汇总

任何遗漏、错误、疑问、建议,请在评论区指出哦~


数论部分

线性筛

线性筛,又称欧拉筛。其时间复杂度为 O(n) ,是一种线性时间复杂度的算法,并因此而得名。

线性筛可以筛出区间 [2,n] 内的所有质数。

核心思想

每个合数有且仅有一次被其最小的质因数标记,从而避免重复操作,达到线性复杂度。

数据结构

1. isPrime[]

一个 bool 类型数组,长度为 n+1 。若 isPrime[i] 的值为 true ,则代表 i 是质数;反之, i 是合数。初始化时所有元素的值都为 true 。

2. primes[]

一般用 vector 存储(即一个动态数组),或者用一个足够大的静态数组。

这个数组内存储已经找到的质数。

算法步骤

1.初始化: 将 isPrime 内的所有元素的值都设置为 true 。(不用把 isPrime[0] 和 isPrime[1] 设置为 false ,因为 0 和 1 都不是质数。但为了严谨性,设置了也未尝不可)

2.遍历每个数 i(从2到n):

  • 若 isPrime[i]==true ,则将 i 丢进 primes 里。

  • 用已找到的素数 primes[j] 与当前数字 i 相乘,标记 i*primes[j] 为合数,即 isPrime[i*primes[j]]=false

  • 若 i 能被 primes[j] 整除,停止内层循环。因为后续 i 与更大素数的乘积,已在之前被筛过。例如 i=4 ,primes[j]=2 时,若不停止,4∗3 会在之后被 6∗2 重复筛除。

  • 遍历结束后, primes 内存储的值就是区间 [2,n] 内的所有质数。

代码示例

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int MAXN=1e6+7;
bool isPrime[MAXN];
vector<int> primes;

void get(int n) {
	for(int i=2;i<=n;i++)
		isPrime[i]=true;
	
	for(int i=2;i<=n;i++) {
		if(isPrime[i])
			primes.push_back(i);

		for(int j=0;j<primes.size()&&i*primes[j]<=n;j++) {
			isPrime[i*primes[j]]=false;
			
			if(i%primes[j]==0)
				break;
		}
	}
}

int main() {
	int x;
	cin>>x;
	
	get(x);
	for(int i=0;i<primes.size();i++)
		cout<<primes[i]<<" ";
	
	return 0;
}

欧几里得算法(辗转相除法)

欧几里得算法是一个求最大公因数(GCD)的算法。

欧几里得算法,又称“辗转相除法”,(“辗”音 zhan ,三声)。

核心思想

两个整数的最大公约数等于其中较小的数和两数相除余数的最大公约数。

即:(a>b)

gcd(a,b)=gcd(b,amodb)

注释:amodb ,a 除以 b 的余数,即 a%b。

显而易见地,可以用递归实现。

算法证明

步骤 1:设定、符号定义

  • 设 d=gcd(a,b),即 d 是 a 和 b 的最大公约数
  • 设 r=amodb,根据带余除法,存在整数 q 和 r(0≤r<b)使得:a=b⋅q+r
  • 需要证明:gcd(a,b)=gcd(b,r)

步骤 2:证明 d 是 b 和 r 的公约数

  1. 由 d=gcd(a,b),得 d∣a 且 d∣b
  2. 由 a=bq+r 可得:r=a−bq
  3. 因为 d∣a 且 d∣b,所以 d∣(a−bq)
  4. 即 d∣r,故 d 是 b 和 r 的公约数

步骤 3:证明 d 是最大公约数(反证法)

  1. 假设存在 d′=gcd(b,r) 且 d′>d
  2. 由 d′=gcd(b,r),得 d′∣b 且 d′∣r
  3. 由 a=bq+r,得 d′∣(bq+r),即 d′∣a
  4. 于是 d′∣a 且 d′∣b,即 d′ 是 a 和 b 的公约数
  5. 但 d=gcd(a,b) 是最大公约数,d′>d 与之矛盾
  6. 故假设不成立,d 就是 b 和 r 的最大公约数

步骤 4:算法终止性证明

  • 算法迭代过程:gcd(a,b)=gcd(b,r0​)=gcd(r0​,r1​)=⋯
  • 余数序列严格递减:b>r0​>r1​>r2​>⋯≥0
  • 根据良序原理,余数必然在有限步内达到 0
  • 当 rk​=0 时:gcd(rk−1​,0)=rk−1​
  • 此时的 rk−1​ 即为所求的最大公约数

代码示例

1.递归版本

#include<iostream>
using namespace std;
int gcd1(int a,int b) {
	if(b==0)
		return a;
	return gcd1(b,a%b);
}
int main() {
	int a,b;
	cin>>a>>b;
	cout<<gcd1(a,b)<<endl;
	return 0;
}

2.迭代版本

#include<iostream>
using namespace std;
int gcd2(int a,int b) {
	while(b) {
		int temp=b;
		b=a%b;
		a=temp;
	}
	return a;
}
int main() {
	int a,b;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值