假期集训第二轮是数论,是一直以来不愿意动手的一个分支,忽然发现什么都不会了QAQ。今天先写素数筛。
参考洛谷博客 zybnxy大佬 %%%一下
bool Is_prime(int n);
{
if(n==1)return false;
if(n==2)return true;
for(int i=2;i<n;i++)
if(n%i==0)return false;
return true;
}
很简单的板子,但是应用在数据较大较多的题目,一定是不可能的。
优化
bool Is_prime(int n);
{
if(n==1)return false;
if(n==2)return true;
for(int i=2;i<=sqrt(n);i++)
if(n%i==0)return false;
return true;
}
然后是6N±1的优化,时间复杂对可以达到
具体讲解是huang_miao_xin大佬
bool Is_prime(int n)
{
if(n==1) return false;
if(n==2||n==3) return true;
if(n%6!=1&&n%6!=5) return false;//不在6的倍数两侧的一定不是质数
for(int i=5;i*i<=n;i+=6)
if(n%i==0||n%(i+2)==0) return false;
return true;
}
#include
using namespace std;
const int MAXN=1000010;
bool prime[MAXN];
void make_prime)()
{
memset(prime,true,sizeof(prime));//这里注意,memset只能用来置0和-1,
//emmm虽然一般它能给你换,但是,,,保险点用手动
prime[0]=prime[1]=false;
int t=sqrt(MAXN);
for(int i=2;i<=t;i++)
{
if(prime[i])
{
for(int j=2*i;j<MAXN,j+=i)
//优化:如果j 从 i * i 而不是从 i + i开始,
//因为 i*(2~ i-1)在 2~i-1时都已经被筛去,所以从i * i开始。
{
prime[j]=false;
}
}
}
return;
}
通过上述代码,我们发现此方法还可以继续优化,因为上述的方法中,每一个有多组因数可能会被筛多次,例如:30会被2,3,5各筛一次导致计算冗余,我们可以对此方法进行改进,得到更加高效的筛法 -----------------欧拉筛(线性筛)
欧拉筛法的基本思想 :在埃氏筛法的基础上,让每个合数只被它的最小质因子筛选一次,以达到不重复的目的。
#include
using namespace std;
const int MAXN=1000010;
bool prime[MAXN];
int Prime[MAXN];
int num=0;
void make_prime()
{
memset(prime,true,sizeof(prime));
prime[0]=prime[1]=false;
for(int i=2;i<=MAXN;i++)
{
if(prime[i])
{
Prime[num++]=i;
}
for(int j=0;j<num&&i*Prime[j]<MAXN;j++)
{
prime[i*Prime[j]]=false;
if(!(i%Prime[j]))//解释见下
break;
}
}
return;
}
当 i是prime[j]的倍数时,i = kprime[j],如果继续运算 j+1,i * prime[j+1] = prime[j] * k prime[j+1],这里prime[j]是最小的素因子,当i = k * prime[j+1]时会重复,所以才跳出循环。
eg:i = 8 ,j = 1,prime[j] = 2,如果不跳出循环,prime[j+1] = 3,8 * 3 = 2 * 4 * 3 = 2 * 12,在i = 12时会计算。因为欧拉筛法的原理便是通过最小素因子来消除。
程序理解见下图,图源自彤云望月大佬
这个方法可以保证每个合数在N/M的最小素因子时被筛出,所以时间复杂度仅为O(N)已经可以满足大部分需求,在竞赛中,这种方法也可以在极短的时间内求出关于N的质数表。
ps:每个正整数都能够以唯一的方式表示成它的质因数的乘积。详情见百度百科。
eg:
但是这个算法的弊端在于,为了判断一个大数是否是素数必须从从头开始扫描,而且空间代价也受不了,故不能离散的判断。
所以,我们要引入更高效的算法——
miller_rabin是一种素性测试算法,用来判断一个大数是否是一个质数。 miller_rabin是一种随机算法,它有一定概率出错,设测试次数为s,那么出错的概率是