一篇不大正经的有关素数的小结
Posted morbidity
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一篇不大正经的有关素数的小结相关的知识,希望对你有一定的参考价值。
众所周知,素数是一个神奇的物种。它呢,不存在非平凡因子(什么是平凡因子呢?即对于任意数n都至少存在两个因子,一个是1,另一个是n本身,我们就叫它俩为n的平凡因子,其他的呢,都为n的不平凡因子(就是与众不同啦))。
这样一想,求它是不是就有很多种方法啦~(悄咪咪说一句,19260817是个质数)
那么OI中就会有非常可爱的求素数及判断素数的题目啦~
xjb乱说一遍关于素数的搞搞:
看代码永远比bb一大堆有的用处
1.一个非常毒瘤的判断素数法子(跑的贼快的那种时间复杂度O($\sqrt{n}$$/3$)):
(我太LJ了,所以不会解释)
首先看一个关于质数分布的规律:大于等于5的质数一定和6的倍数相邻。例如5和7,11和13,17和19等等;
证明:令x≥1,将大于等于5的自然数表示如下:
·· 6x-1,6x,6x+1,6x+2,6x+3,6x+4,6x+5,6(x+1),6(x+1)+1 ···
可以看到,不和6的倍数相邻的数为6x+2,6x+3,6x+4,由于2(3x+1),3(2x+1),2(3x+2),所以它们一定不是素数,再除去6x本身,显然,素数要出现只可能出现在6x的相邻两侧。因此在5到sqrt(n)中每6个数只判断2个,时间复杂度O($\sqrt{n}$$/3$)。
这种方法裁剪了不和6的倍数相邻的数,虽然都没有降低时间复杂度的阶数,但都一定程度上加快了判断的速度。
inline bool 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*i<=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.埃氏筛总得听过吧
#include"bits/stdc++.h"
using namespace std;
const long long maxn=10000007+10;
const long long maxp=700000;
int vis[maxn];//i是合数vis为1,i是素数,vis为0
long long prime[maxp];
void sieve(long long n) {
long long m=(long long)sqrt(n+0.5);
memset(vis,0,sizeof(vis));
for(long long i=3; i<=m; i=i+2) {
if(!vis)for(long longj=i*i; j<=n; j+=i) vis[j]=1;
if(i*i>n)break;
}
}
long long gen(long long n) {
ieve(n);
long long c=1;
rime=2;
for(long long i=3; i<=n; i=i+2)
if(!vis) rime[c++]=i;
return c;
}
int main() {
freopen("in.in","r",stdin);
freopen("biao.out","w",stdout);
long long n,c;
cin>>n;
c=gen(n);
for(long long i=0; i<c; i++)
rintf("%lld",prime);
cout<<endl<<c;
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 素数个数
综上所述:我还是喜欢毒瘤,噗嗤
以上是关于一篇不大正经的有关素数的小结的主要内容,如果未能解决你的问题,请参考以下文章