基础数论算法(六) 素数的筛法与质因数分解
发布时间
阅读量:
阅读量
素数筛法
如果我们需要多次判断是不是素数时,比起无数次的枚举、测试,还是提前筛出一张素数表比较好
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
全部评论 (0)
还没有任何评论哟~
