数学基本知识整理

撰写原因

由于在刷题过程中总是会遇到一些比较基础的数学知识,但是由于记忆模糊所以总是会想的很吃力,所以尝试写下这篇文章来记录自己容易忘记的一些知识,希望自己能够不断更新这篇文章,使之较为全面。

公约数(common factor)

公约数,亦称“公因数”。它是一个能被若干个整数同时均整除的整数。如果一个整数同时是几个整数的约数,称这个整数为它们的“公约数”;公约数中最大的称为最大公约数。对任意的若干个正整数,1总是它们的公因数。公约数与公倍数相反。
扩展知识点:
求解最大公约数常用欧几里得算法(即辗转相除法),一般用 gcd(a, b) 来表示 a 和 b 的最大公约数。
欧几里得算法基于下面这个定理:
设 a 、b 均为正整数,则 gcd(a, b) = gcd(b, a % b)。
用中文解释就是指两个数的最大公约数等于较小数与两个数相除所得余数的最大公约数。
相关代码:

int gcd(int a, int b)
{
	if(b == 0) return a;
	else return gcd(b,  a % b);
}
//更简洁的写法是:
int gcd(int a, int b)
{
	 return !b ? a : gcd(b, a % b);
}

希望能够将之记牢。

公倍数(common multiple)

公倍数(common multiple)是指在两个或两个以上的自然数中,如果它们有相同的倍数,这些倍数就是它们的公倍数。公倍数中最小的,就称为这些整数的最小公倍数(lowest common multiple)。
扩展知识点:
一般用 lcm(a, b) 来表示 a 和 b 的最小公倍数。最小公倍数的求解在最大公约数的基础上进行,当得到 a 和 b 的最大公约数 d 之后,可以马上得到 a 和 b 最小公倍数是 a*b / d。
自我理解:
当想要求得 a,b 之间的最小公倍数时,我们通常的想法是,先将两者一起化简到最简状态,如 4 : 6,化为最简:2 : 3;然后将两者相乘之后再乘以之前为了化简所共同除的数,就会得到还原之后的最小公倍数,仔细研究会发现,要想化简到最简状态,直接同时除以最大公约数就行,则可以表示为 a / d b / d d = ab / d;即所得方程。
注意点:
由于 a
b 在实际运算中有可能溢出,因此更加恰当的写法是 a / d * b。

素数(prime number)

质数又称素数。一个大于1的自然数,除了1和它自身外,不能被其他自然数整除的数叫做质数;否则称为合数。
应特别注意的是: 1既不是素数也不是合数。
扩展知识点:

  1. 如何判定给定的正整数 n 是否是质数;
  2. 如何在较短的时间内得到 1 ~ n 的素数表。

素数的判断
根据定义,一个整数要被判断是素数,需要判断 n 是否能被 2,3,…… n - 1 中的一个整除,若能,则不是质数,不能则是素数。但是这种方法复杂度较高为O(n)。容易推导只需判断 2,3,…… sqrt(n) 中任一个能否被整除(这里的根号 n 向下取整),若能,则为非素数,至于为什么是根号 n 向下取整,这里不多赘述。

素数表的获取
若从1开始遍历到 n - 1来获取素数表,在数据较少的时候还可以使用,但是数据一旦超过105时,就将力不从心。
下面介绍一种最简单且容易理解的一种更高效的算法,叫做 “埃氏筛法”, Eratosthenes筛法,复杂度为O(nloglogn)。更优的欧拉筛法可以达到O(n),此处不予赘述。
素数筛法关键在于 “筛”。算法从小到大枚举所有数,对每一个素数,筛去它所有倍数,剩下的就全是素数了。 如何理解呢?可以自己尝试手算一下 1~15中的素数,先确定 2 是素数,然后删除2的所有倍数,然后找到下一个没删除的素数如此循环,直到到最后一个数字。其实很容易理解,如果可以由素数的倍数所表示,那么一定不是素数,而没有被之前所留下的素数翻倍所删除的数字则一定是只能被1和本身整除,所以也是素数。
代码如下(求解100以内的素数表的程序):

#include<cstdio>
const int maxn = 101;
int prime[maxn], pnum = 0;
bool p[maxn] = {0};
void find_prime()
{
 for(int i = 2; i < maxn; i++)
 {
  if(p[i] == false)
  {
   prime[pnum++] = i;
   for(int j = i + i; j < maxn; j += i)
   {
    p[j] = true;
   }
  }
 }
}
int main()
{
 find_prime();           //这个一定不要忘记,预处理
 for(int i = 0; i < pnum; i++)
 {
  printf("%d", prime[i]);
  if(i != pnum - 1)printf(" ");
 }
 return 0;
}

优化
这里有个一个小优化,j 从 i * i 而不是从 i + i开始,因为 i*(2~ i-1)在 2~i-1时都已经被筛去,所以从i * i开始。
代码如下

void find_prime()
{
	 for(int i = 2; i < maxn; i++)
	 {
		  if(p[i] == false)
		  {
		   	prime[pnum++] = i;
		   	int j = i * i;
		   	while(j < maxn)             //注意保证j不会超出maxn的范围,否则就会段错误
		   	{
		   		p[j] = true;
		   		 j += i
		   	}
		 }
	}
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值