您的位置:首页 > 其它

基础数论算法(六) 素数的筛法与质因数分解

2017-08-12 14:50 190 查看

素数筛法

如果我们需要多次判断是不是素数时,比起无数次的枚举、测试,还是提前筛出一张素数表比较好

Eratosthenes筛法

一般情况下够用的筛法。复杂度nlnlnn,关键是不容易写错。还有别问我这个复杂度怎么算出来的。实现非常简单。

#include <iostream>
#include <cstring>
using namespace std;
#define MAXN 1000001
int main(){
bool notprime[MAXN];
memset(notprime,0,sizeof(notprime));
notprime[1]=1;
for(int a=2;a<MAXN;a+=(a==2?1:2))
if(!notprime[a])  //如果不加的话复杂度nlnn
for(int k=2;a*k<MAXN;++k)
notprime[k*a]=1;
for(int i=1;i<MAXN;++i)
if(!notprime[i])
cout<<i<<endl;
return 0;
}


线性筛

又称欧拉筛,复杂度几乎是O(n),甚至直接看成O(n)即可。其秘诀就是保证每个数都是被自己最小的因子筛掉的。

它的实现是这样的:对i,分别筛掉i*prime[j],其中prime[j]表示所有小于i的素数的数组。如果prime[k]|i,则直接推出循环,因为该数一定会被其他数筛掉。

在数据比较大的时候,欧拉筛会明显占优势。缺点是容易写错。

#include <iostream>
#include <cstring>
#define MAXN 14
using namespace std;
bool notprime[MAXN];
int prime[MAXN];
int main(){
notprime[1]=true;
int count=0;
for(int i=2;i<MAXN;++i){
if(!notprime[i])
prime[++count]=i;
for(int j=1;j<=count;++j){
if(prime[j]*i>MAXN)
break;
notprime[prime[j]*i]=true;
if(i%prime[j]==0)
break;
}
}
for(int i=1;i<MAXN;++i)
if(!notprime[i])
cout<<i<<endl;
}


欧拉筛的原理我曾经想了一个上午也没有搞懂……所以实在不行就背代码吧。

质因数分解

分解质因数还是很有意义的一件事,实现起来也不算太难。

试除法

可以借助筛出的素数分解,这样会降些复杂度,这里就直接写不需要提前筛的算法了。

#include <iostream>
#include <vector>
using namespace std;
typedef long long LL;
int main(){
LL a;
cin>>a;
vector<pair<LL,int> > v;
vector<pair<LL,int> >::iterator vi;
for(int i=2;i*i<=a;i+=(i==2?1:2)){
if(a%i==0){
int count=0;
while(a%i==0)
++count,a/=i;
v.push_back(make_pair(i,count));
}
}
if(a!=1) v.push_back(make_pair(a,1));
for(vi=v.begin();vi!=v.end();++vi)
cout<<vi->first<<" "<<vi->second<<endl;
}


Pollard算法

无论如何,我们都需要记住,这门科学是RP科学。因此,随机化算法一定是一个不可或缺的部分!

不过虽然这么说……我觉得NOIP大概用不到这玩意吧,反正我是完全没有看懂……如果想搞懂的话可以参考

http://www.cnblogs.com/jackiesteed/articles/2019910.html

http://qkxue.net/info/120352/Pollard-rho
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息