素数(质数)
定义:只有1和它本身作为约数(因数的数)。
合数
不是质数的自然数是合数。(就是除了他自己本身还有别的约数)
质因数
定义:一个数即是质数,也是某数x的因数,叫做x的质因数。
判断质数
试除法
- 循环枚举x的约数,如果最后只能被他自己除掉,那么就是质数,算法的复杂度是o(n)
bool isPrime(int x){
if(x<2) return false;
for(int i=2;i<x;i++){
if(x%i==0)return false;
}
return true;
}
枚举优化
我们可以注意到,约数都是成对出现的,也就是说,如果一个数n的约数是d,那么n/d也是n的约数。所以实际上我们可以只枚举每一对约数中的一个即可,优化后的算法复杂度大约是根号n,优化后的代码是
bool isPrime(int x){
if(x<2) return false;
for(int i=2;i<=x/i;i++){//只要比较小的那个约数,这里比较的不是数量,是两约数的大小关系。
if(x%i==0)return false;
}
return true;
}
分解质因数
在数学上我们用短除法来分解一个数的质因数。如下图所示
什么意思呢?就是从最小的质数开始去除这个数,直到除出来的数是1(上面的图还有最后一步),分解就结束。
在计算机也是枚举质数来分解质因数
void divide(int x){
for(int i=2;i<=x;i++){//等于号是为了除以本身
int res=0;
if(x%i==0){//满足该条件的i一定是一个质数
while(x%i==0){
x/=i;
res++;//res是指数,i是底数
}
printf("%d %d\n",i,res);
}
}
}
也许会有人有一个疑问,明明枚举的是质数,怎么变成了枚举所有数呢?会不会有合数被枚举了出来呢?
答案是不会的。因为当我们枚举到i且if的条件成立时的时候,说明前面的2->i-1都是不能被现在的x整除的(是现在的x,x一直在变化,联系在数学求质因数时的短除法),那么又因为x是i的倍数,那么我们知道前面的2->i-1也是不能被i整除的,那么我们就知道i一定是质数。每一个i都是质数,所以当然也就不会有合数被枚举了。
优化分解质因数的方法
首先我们要知道。
- 一个合数x最多只包含一个大于sqrt(x)的质因子(如果有两个那么乘起来就会大于x)。
所以我们就可以先枚举小于sqrt(x)的数(质数),如果最后剩下的x仍然大于1,那么再去单独处理输出。
void divide(int x){
for(int i=2;i<=x/i;i++){//这里是需要x的,因为我们是在枚举质因数,有可能自己本身也是需要一次的
int res=0;
if(x%i==0){
while(x%i==0){
x/=i;
res++;
}
printf("%d %d\n",i,res);
}
}
if(x>1) printf("%d 1\n",x);
}
-----acwing跟y总学习的笔记。