ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

基础数论知识

2021-11-14 22:06:00  阅读:169  来源: 互联网

标签:prime 数论 质数 知识 基础 sqrt int 因子 倍数


本人是刚学算法的萌新,还请大佬们指正。

这篇文章主要是介绍质数,约数,欧拉函数,快速幂,扩展欧几里得算法,中国剩余定理,高斯消元,求组合数,容斥原理,博弈论的相关内容。

现在还在完善ing,之后会补上一些例题

1.质数

1.1质数的判定(试除法) O(sqrt(n))

质数的定义:该数的因子只有1和本身。

输入一个数判断它是否是质数

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

1.2分解质因数(试除法)  O(sqrt(n))

n={a_{1}}^{p1}{a_{2}}^{p2}{a_{3}}^{p3}....{a_{k}}^{pk}(其中a1~ak均为质数) 

题意:输入n,每行输出a_{i},p_{i},

思路:由于不存在一个数有两个>sqrt(n)的质因子(反证法:若n能分解成两个>sqrt(n)的质因子,则这两个质因子的乘积必然>n),所以只需枚举2~sqrt(n)判断该数的质因子,若i是n的质因子,则一直n/=i,直到n%i!=0次数就是p_{i}。需要注意的是我们是枚举2~sqrt(n)如果n最后不等于1,那么n就是最后一个>sqrt(n)的质因子。代码如下:

void divide(int n) {
	for(int i=2; i<=n/i; i++) {
		if(n%i==0) { //这里i绝对为质数
			int s=0;
			while(n%i==0) {
				n/=i;
				s++;
			}
			printf("%d %d\n",i,s);
		}
	}
	if(n!=1) printf("%d %d\n",n,1);//可能存在一个>sqrt(n)的质因子 ;
}

1.3筛质数

1.3.1埃氏筛法      算法复杂度o(nloglogn)

求1~n里面的质数

思路:

把2的倍数筛了:4,6,8,10,12,14,16,18,20,22.....

把3的倍数筛了:6,9,12,15,18,21,24,27,30,33......

把4的倍数筛了:4,8,12,16,20,24,28,32,36,40.....

把5的倍数筛了:5,10,15,20,25,30,35,40,45,50.....

把6的倍数筛了:6,12,18,24,30,36,42,48,54,60.....

把7的倍数筛了...........

.........

那么没被筛过的数就是质数啦(2,3,5,7,11,13,15.....)

代码如下:

#include <iostream>
using namespace std;
const int N=1e6;
bool st[N];//是否被筛过 
int prime[N],cnt;
void get_prime(int n){
	for(int i=2;i<=n;i++){
		if(!st[i]){
			prime[cnt++]=i;			 
		}
		for(int j=i+i;j<=n;j+=i) st[j]=true; 
	}
	for(int i=0;i<cnt;i++) cout<<prime[i]<<endl;
}
int main(int argc, char** argv) {
	int n;
	cin>>n;
	get_prime(n);
	return 0;
}

但是仔细想想,能不能优化呢,比如我把2的倍数筛完了,我需不需要筛4的倍数呢,需不需要筛6的倍数呢,同样的道理我既然把3的倍数筛过了,需不需要筛6的倍数呢,还需不需要把9的倍数筛了呢,显然是不需要的。

所以我们只需要稍微变一下就行了,从而优化了算法。

代码如下:(唯一的区别在于for循环的位置)

#include <iostream>
using namespace std;
const int N=1e6;
bool st[N];//是否被筛过
int prime[N],cnt;
void get_prime(int n) {
	for(int i=2; i<=n; i++) {
		if(!st[i]) {
			prime[cnt++]=i;
			for(int j=i+i; j<=n; j+=i) st[j]=true;
		}

	}
	for(int i=0; i<cnt; i++) cout<<prime[i]<<endl;
}
int main(int argc, char** argv) {
	int n;
	cin>>n;
	get_prime(n);
	return 0;
}

1.3.2线性筛法     算法复杂度o(n)

这是我们需要掌握的,线性筛用处范围很广,很多算法都是由它扩展的。

首先要知道什么是线性:利用了每个合数必有一个最小素因子每个合数仅被它的最小素因子筛去正好一次。所以为线性时间。(关键)
代码中体现在:
if(i%prime[j]==0)break;(最需要理解的部分)
 

废话不多说,上代码:

#include <iostream>

using namespace std;
const int N=1e6;
int p[N],cnt=0;
bool st[N];
void get_prime(int n){
	for(int i=2;i<=n;i++){
		if(!st[i])	p[cnt++]=i;
			for(int j=0;p[j]<=n/i;j++){
				st[p[j]*i]=true;
				if(i%p[j]==0) break;
			}
	}
	for(int i=0;i<cnt;i++) cout<<p[i]<<endl;
}
int main(int argc, char** argv) {
	int n;
	cin>>n;
	get_prime(n);
	return 0;
}

标签:prime,数论,质数,知识,基础,sqrt,int,因子,倍数
来源: https://blog.csdn.net/qq_54125134/article/details/121316552

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有