初等数论一

一.质数

  1. 定义
    大于1的整数中,只有1和它本身的约数的整数就叫做质数,也叫作素数。

  2. 质数的判定
    (1)试探法,时间复杂度为O(n)

#include<iostream>
#include<algorithm>
using namespace std;
int main(){
    ios::sync_with_stdio(false),cin.tie(0);
    int n;
    cin >> n;
    if (n < 2)  return 0;
    for (int i = 2; i <= n; i++)
        if (n % i == 0){
            cout << n << "不是质数" << "\n";
            return 0;
        }
    cout << n << "是质数" << "\n";           
    return 0;
}

(2)试探法优化,时间复杂度O(sqrt(n))
推理:因为如果d是n的约数,那么n/d也是n的约数,所以判定条件范围可以缩小到d<=n/d
循环判定的条件不推荐写i<=sqrt(n)
原因:每次循环都得执行一次sqrt(n),而且sqrt这个函数本身也不快
循环判定的条件不推荐写ii <= n
原因:如果i定义的是int类型,假设判定的数n=2147483647,那么(i+1)
(i+1)就会溢出,影响结果的判定

#include<iostream>
#include<algorithm>
using namespace std;
int main(){
    ios::sync_with_stdio(false),cin.tie(0);
    int n;
    cin >> n;
    if (n < 2)  return 0;
    for (int i = 2; i <= n / i; i++)
        if (n % i == 0){
            cout << n << "不是质数" << "\n";
            return 0;
        }
    cout << n << "是质数" << "\n";           
    return 0;
}
  1. 分解质因数
    (1)试探法,时间复杂度O(n)
    可能会有人觉得这样除的话可能会有合数,但是在n%i==0成立之前所有的i值都是不行的,不是n的约数,也就是2-i-1的数。算到第一个约数i的时候,这个i一定是质数。
#include<iostream>
#include<algorithm>
using namespace std;
int main(){
    ios::sync_with_stdio(false),cin.tie(0);
    int n;
    cin >> n;
    if (n < 2)  return 0;
    for (int i = 2; i < n; i++){   
        if (n % i == 0){
            int s = 0;
            while(n % i == 0){
                n /= i;
                s++;
            }
            cout << i << " * " << s;
        }
        
    }         
    if (n > 1)  cout << " * " << n << "\n";
    return 0;
}

(2)试探法优化,时间复杂度O(sqrt(n))
优化后的时间复杂度虽然也是O(sqrt(n)),但是和质数判断的时间复杂度不一样。分解质因数最好可以达到O(logn),例如n是2^k。
优化一样是从判定条件去优化,和判断质数一样

#include<iostream>
#include<algorithm>
using namespace std;
int main(){
    ios::sync_with_stdio(false),cin.tie(0);
    int n;
    cin >> n;
    if (n < 2)  return 0;
    for (int i = 2; i < n / i; i++){   
        if (n % i == 0){
            int s = 0;
            while(n % i == 0){
                n /= i;
                s++;
            }
            cout << i << " * " << s;
        }
        
    }         
    if (n > 1)  cout << " * " << n << "\n";
    return 0;
}
  1. 筛质数
    (1)核心思想:删除整数的倍数
    (2)朴素筛
    把2~n的所有数的倍数都筛一遍,无论合数还是质数
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 1e5 + 10;
int q[maxn],cnt = 0;
bool st[maxn] = {false};
int main(){
    ios::sync_with_stdio(false),cin.tie(0);
    int n;
    cin >> n;
    for (int i = 2; i <= n; i++){
        if (!st[i]) q[cnt++] = i;
        for (int j = i + i; j <= n; j+=i)   st[j] = true;
    }
    for (int i = 0; q[i]; i++)  cout << q[i] << " ";
    return 0;
}

时间复杂度分析:
时间复杂度分析
(3)埃氏筛(爱氏筛)
a.在筛选范围n以内,删除所有质数的倍数
b.埃氏筛是朴素筛的改进,代码差不多,无非就是把一个for循环提到了if里面来
c.质数定理:1-n中有n/lnn个质数
d.时间复杂度分析:由朴素筛时间复杂度可以推出埃氏筛的时间复杂度为O(log(logn))
e.由于是线性的筛选方法,所以时间复杂度是O(n)

#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 1e5 + 10;
int q[maxn],cnt = 0;
bool st[maxn] = {false};
int main(){
    ios::sync_with_stdio(false),cin.tie(0);
    int n;
    cin >> n;
    for (int i = 2; i <= n; i++){
        if (!st[i]) {
            q[cnt++] = i;
            for (int j = i + i; j <= n; j+=i)   st[j] = true;
        }     
    }
    for (int i = 0; q[i]; i++)  cout << q[i] << " ";
    return 0;
}

(4)欧拉筛(线性筛)
a.若n≈10^6,线性筛和埃氏筛的时间效率差不多,若 n≈10^7,线性筛会比埃氏筛快了大概一倍
b.原理:让每个合数只筛选一次,被它的最小质因子筛选
c.时间复杂度O(n)

#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 1e5 + 10;
int q[maxn],cnt = 0;
bool st[maxn] = {false};
int main(){
    ios::sync_with_stdio(false),cin.tie(0);
    int n;
    cin >> n;
    for (int i = 2; i <= n; i++){
        if (!st[i]) q[cnt++] = i;//q数组里面存放的是质数,按升序进行排序
        for (int j = 0; q[j] <= n / i; j++){
            st[q[j] * i] = true;//q[j]是质数,i只是充当倍数
            //能break说明i是这个素数的倍数,q[j]是最小质因子
            //既然是最小质因子就要退出,不然会导致后面的合数也被筛选,从而导致重复筛选
            if (i % q[j] == 0)  break;
        }
    }
    for (int i = 0; q[i]; i++)  cout << q[i] << " ";
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值