一篇不大正经的有关素数的小结

素数:

也称质数、不可约数,不存在非平凡因子。ios

平凡因子:

即对于任意数\(n\)都至少存在两个因子,一个是\(1\),另外一个是\(n\)自己,咱们就叫它俩为\(n\)的平凡因子,其余的,都为n的不平凡因子。c++

性质:

\(\pi (n)\)为不超过\(n\)的质数个数
那么,\(\pi (n) \backsim \frac {n}{\ln n}\)\(n\)越大,估计的越准确)算法

质因数分解:

Code:数组

inline int factorize(int x,int p[]) {
    int cnt=0;
    for(int i=2; i*i<=x; ++i) {
        if(x%i==0) {
            p[cnt++]=i;
            x/=i;
        }
    }
    if(x>1) p[cnt++]=x;
    return cnt;
}

例题:

质数有无限个,如何证实?网络

反证法:假设质数是有限的
\(\because假设为p_1,p_2,\cdots p_n\)
\(\therefore M=p_1*p_2*\cdots p_n+1\)
\(又\therefore M \bmod p_1=1\)
\(M \bmod p_2=1\)
\(\cdots\)
\(M \bmod p_n=1\)
\(\therefore M \bmod 任何质数都是1,M不是任何质数的倍数,M是质数,与假设冲突,因此质数有无限个\)dom

这样一想,求它是否是就有不少种方法啦~(\(Emma,19260817\)是个质数)
1.一个毒瘤的判断素数法子(跑的贼快的那种,时间复杂度 \(O(\sqrt{n}/3)\)):优化

首先看一个关于质数分布的规律:
\(\geq5\)的质数必定和\(6\)的倍数相邻。
\(证实:令x\geq 1,将\geq 5的天然数表示以下:\)
\(\cdots 6x-1,6x,6x+1,6x+2,6x+3,6x+4,6x+5,6(x+1),6(x+1)+1 \cdots\)
\(能够看到,不和6的倍数相邻的数为6x+2,6x+3,6x+4,因为2(3x+1),3(2x+1),2(3x+2),因此它们必定不是素数,再除去6x自己,显然,素数要出现只可能出如今6x的相邻两侧。\)
这种方法裁剪了不和\(6\)的倍数相邻的数,虽然都没有下降时间复杂度的阶数,但都必定程度上加快了判断的速度。spa

inline int prime(int n) {
    if(n==1) return false;
    if(n==2 || n==3) return true;
    if(n%6!=1 && n%6!=5) return false;
    for(register int i=5; i<=sqrt(n); i+=6)
        if(n%i==0 || n%(i+2)==0) return false;
    return true;
}

2.很是朴素的一种算法(判断有没有能整除的数)

#include<bits/stdc++.h>
using namespace std;
int main() {
    int n;
    cin>>n;
    for(int i=2; i<=n; i++) {
        if(n%i==0) {
            cout<<"flase";
            return 0;
        } else {
            cout<<"true";
            return 0;
        }
    }
}

3.网络上流传的素数打表:

/*
遇到素数须要打表时,先估算素数的个数:
num = n / lnx;
num为大概数字,越大偏差越小(只是估计,用于估算素数表数组大小)
这个打表法效率貌似很高,网上说几乎达到了线性时间(不知道是真是假=。=)
*/
#include<iostream>
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
#define maxn 10000000
using namespace std;
bool visit[maxn+1000000];
int prime[maxn],n; ///prime的大小大概估计一下再开数组。大概是(x/lnx)
void getprime() {
    memset(visit, false, sizeof(visit));
    int num = 0;
    for (int i = 2; i <= n; ++i) {
        if ( !visit[i] )  prime[++num] = i;
        for (int j = 1; j <= num && i * prime[j] <= n ;  j++) {
            visit[ i  *  prime[j] ]  =  true; 
            if (i % prime[j] == 0) break; 
        }
    }
    for(int i=2;i<=n;i++){
        if(visit[i]==false)
        cout<<i<<' ';
    }
}
int main() {
    freopen("素数打表.txt","w",stdout); 
    scanf("%d",&n);
    getprime();
    return 0;
}

4.弟弟通常的朴素打表:

#include<bits/stdc++.h>
using namespace std;

int g_g(int x) {
    int flag=1;
    for(int i=2; i<=sqrt(x); ++i) {
        if(x%i==0)
            flag=0;
    }
    if(flag==1)
        return 1;
    else
        return 0;
}
int main() {
    freopen("sushu.out","w",stdout);
    for(int i=9784010; i<=100000000; ++i) {
        if(g_g(i)) {
            cout<<i<<",";
        }
    }
    return 0;
}

5.有点小优化的朴素判断:

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

6.埃氏筛总得听过吧(stm找的一个代码得明白)

#include<bits/stdc++.h>
using namespace std;
int n,m;
int fw;
int kk;
bool a[100000000];
int main()
{
    cin>>n>>m;
    memset(a,0,sizeof(a));
    fw=sqrt(n+0.5);//防止四舍五入
    a[1]=1;//不判断一,直接赋值
    for(int i=2;i<=fw;i++)//从二的倍数开始找
    {
        if(a[i]==0)//优化一,只有在a[i]不是合数下判断。
        {
            for(int j=i*i;j<=n;j+=i)//j=i*i,是重点,应为2*i等已经被判断过了
                a[j]=1;    
        }
    }
    for(int i=1;i<=m;i++)
    {
        cin>>kk;
        if(a[kk]==0)
            cout<<"Yes"<<endl;
        else
            cout<<"No"<<endl;
    }
    return 0;
}

7.miller rabin 算法(很**,反正我不会)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <map>
#define ll long long
using namespace std;
const int times = 20;
int number = 0;
map<ll, int>m;
ll Random(ll n) { //生成[ 0 , n ]的随机数
    return ((double)rand()/RAND_MAX*n+0.5);
}
ll q_mul(ll a, ll b, ll mod) { //快速计算 (a*b) % mod
    ll ans=0;
    while(b) {
        if(b&1) {
            b--;
            ans=(ans+a)%mod;
        }
        b/=2;
        a=(a+a)%mod;
    }
    return ans;
}
ll q_pow(ll a,ll b,ll mod) { //快速计算 (a^b) % mod
    ll ans=1;
    while(b) {
        if(b&1) {
            ans=q_mul(ans,a,mod );
        }
        b/=2;
        a=q_mul(a,a,mod);
    }
    return ans;
}
bool witness(ll a,ll n) { //miller_rabin算法的精华
    //用检验算子a来检验n是否是素数
    ll tem=n-1;
    int j=0;
    while(tem%2==0) {
        tem/=2;
        j++;
    }
    //将n-1拆分为a^r * s
    ll x=q_pow(a,tem,n); //获得a^r mod n
    if(x==1||x==n-1) return true;//余数为1则为素数
    while(j--) { //不然试验条件2看是否有知足的 j
        x=q_mul(x,x,n);
        if(x==n-1)return true;
    }
    return false;
}
bool miller_rabin(ll n) { //检验n是不是素数

    if(n==2)return true;
    if(n<2||n%2==0)return false;//若是是2则是素数,若是<2或者是>2的偶[]数则不是素数
    for(register int i=1; i<=times; i++) { //作times次随机检验
        ll a=Random(n-2)+1;//获得随机检验算子 a
        if(!witness(a,n))return false;//用a检验n是不是素数
    }
    return true;
}
int main() {
    ll x;
    while(cin>>x) {
        if(miller_rabin(x))
            cout<<"Yes"<<endl;
        else
            cout <<"No"<<endl;
    }
    return 0;
}

刮搜几道弟弟(我这种人)喜欢作的题:

AT261 与えられた数より小さい素数の個数について
AT807 素数、コンテスト、素数
AT1476 素数断定
P3383 【模板】线性筛素数
P3912 素数个数code

综上所述:我仍是喜欢毒瘤,噗嗤ci

相关文章
相关标签/搜索