在m和n之间生成素数[重复]
Posted
技术标签:
【中文标题】在m和n之间生成素数[重复]【英文标题】:Generating prime numbers between m and n [duplicate] 【发布时间】:2014-05-22 13:38:01 【问题描述】:这是spoj.com上的练习题http://www.spoj.com/problems/PRIME1/..
我的提交给出了“超出时间限制”
约束是:1
我根据eratosthenes的筛子写了如下代码,
void sieve(int m,int n)
bool prime[1000005];
bool prime2[1000005];
int i;
int k;
prime[0]=1;
prime[1]=1;
int mi=sqrt(n);
for (int i=2; i<=mi; i++)
if (prime[i]==0)
for ( k=i*i; k<=n; k+=i)
if(k<=mi)
prime[k]=1;
if(k>=m)
prime2[k-m]=1;
int u=min(n,(int)1000000);
for(i=0;i<u;i++)
if(prime2[i]==0 && i+m>=2 && i+m<=n)
printf("%d\n",i+m);
printf("\n");
这里的“m”和“n”是我们必须生成素数的数字范围。
我面临的问题是当我将输入作为 100000000 100100000 运行需要 1.04 秒 (ideone.com C++ 4.3.2) 和 10000000 10100000 需要0.07秒
1)为什么时代差异如此之大,是什么原因造成的?
2) 有没有更快的方法来解决这个问题?
【问题讨论】:
不要每次都重新计算筛子,计算一次,然后对每个输入进行迭代。代码也有点乱,首先你声明 i,然后在 for 循环中隐藏它,u 检查没有多大意义,等等。 -EDIT- 等等!您是否每次都认真地从 0 迭代到最大值并检查该索引是否在范围内? 你真的这样缩进你的代码吗?你发在这里的时候不觉得丢脸吗?你没有想到“嗯,我在公开发布这个并要求人们免费查看它,所以也许我应该让它看起来不像撒旦的后路,更像是快乐的 C++ 代码?” @user2657257:你有很多关于编程的知识——仅仅因为某些东西似乎可以工作并不意味着它没有错误。您肯定可以看到这些数组从未初始化,因此您有未定义的行为? @Dukeling 好吧,Erastothenes 筛子的复杂度为O(n log log n)
,你有 6 秒的时间来完成这项任务。对其进行惰性评估非常非常低效,因此通过消除过程,您只需要计算完整的筛子(并享受所述算法的相当好的缓存行为),然后对其进行迭代。
@user2657257 在调试模式下可以。在发布时,绝对不是。
【参考方案1】:
1) 为什么时代差异如此之大,是什么促成了 这 ?
时间差异即将到来,因为两个范围内构建筛子所需的时间不同。更大的数字会更高。
2) 有没有更快的方法来解决这个问题?
如 cmets 中所述,您正在计算每个测试用例的筛子。您只需要构建一次筛子,并且最多只能构建 sqrt(1000000000) = 100000。
我的解决方案(很久以前)如下:
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <iterator>
bool is_prime (const int& n, std::vector<int>& v);
int main()
int t;
std::cin >> t;
std::vector<int> prime_array;
// build the sieve
for (int i=2; i<=100000; i++)
if ( is_prime( i, prime_array ) )
prime_array.push_back( i );
while (t--)
long long m;
long long n;
std::cin >> m;
std::cin >> n;
if (m<2) m = 2;
//check for the prime numbers in the range.
for (int i=m; i<=n; i++)
if ( is_prime( i, prime_array ) )
std::cout << i << std::endl;
std::cout << std::endl;
return 0;
// we need to check for prime factors up to sqrt(n)
bool is_prime (const int& n, std::vector<int>& v)
double root = sqrt (n);
std::vector<int>::iterator it = v.begin();
while ( it != v.end() && *it <= root )
if (!( n % *it)) return 0;
it++;
return 1;
【讨论】:
修改了我的代码,正如你所建议的那样,被接受了。有点慢,但现在可以了以上是关于在m和n之间生成素数[重复]的主要内容,如果未能解决你的问题,请参考以下文章