algorithm - 求n 次素数的算法

  显示原文与译文双语对照的内容
130 5

我试图在SPOJ上解决一个问题。我们需要计算第n 双双素数( 与 2不同的素数) 。n 可以为 10 ^5.我试图使用筛选器,我得筛选最多 10个 ^8,但是时间限制是 strict(2s) 和precalculation的时间。我注意到人们在 0.00秒内已经经解决了这个问题,所以我在google上查找了一个公式,。请有人指点我?

请提前致谢 !

时间:原作者:0个回答

111 3

所以基本上,筛选到 20,000,000足够,根据,。使用Eratosthenes平原筛选器,机率为 odds,在 C++ ( 你用的是什么语言) 中使用 vector<bool>

追踪筛圈内的双素数。在单独的向量中存储对的较低元素,如果要求 out-of-order ( 小于前一个) 索引,请从这里存储中获取素:

size_t n = 10000000, itop=2236;
vector<bool> s;
vector<int> twins;
s.resize(n, true);
int cnt, k1, k2, p1=3, p2, k=0;
cin>> cnt;
if( cnt--> 0 )
{
 cin>> k1;
 for( size_t i=1; i <n; ++i )//p=2i+1
 {
 if( s[i] )
 {
 p2 = 2*i+1;
 if( p2-p1 == 2 ) { ++k; twins.push_back(p1); }
 if( k==k1 )
 { 
 cout <<p1 <<"" <<p2 <<endl;
. . ....

等待 1.05秒的( 0.18秒 Ideone ) 。或者解解逻辑- 只是预先计算 100,000双重素对,然后在一个单独的循环中访问它们。

原作者:
107 4

出于好奇,我解决了问题:使用Eratosthenes的两种变体。在 0.93和 0.24的测试机上完成了第一个变体,第二个。对于比较,在我的计算机上,第一个完成了 0.08和第二个在 0.04.

第一个是奇数的标准筛,第二个略微精细的筛选除了 3的倍数以外的倍数。

SPOJ的测试机器太旧,比一般的近期框运行得长很多;因此,它们的缓存很小,所以要保持小的缓存。

这样,Eratosthenes的筛子就足够快了。但是,保持内存使用率是非常重要的。第一个变量,每个数字使用一个字节,在我的框中给出了"超出时间限制",但在。在给定的时间内,根据SPOJ测试机的特点,用来解决它。

通过进一步减少筛选的空间,在SPOJ机器上得到了一个显著的加速( 运行时间 0.14 s ) 。since ( 3,5 ) - 除了第一个素数 twins,你不需要知道两个数字的组合,如果 k 不产生双素数对,就只需筛选索引。

( 6*k + 1 可以被 5整除,仅当k = 5*m + 4对于某些 m6*k - 1 可以以被除去 5,如果对某些 mk = 5*m+1,则 5将标记为。5*m ± 1, m> = 1因为不产生双素数。类似地,6*k+1 可以被 13整除,只有当k = 13*m + 2对于某些 m6*k - 1,如果且仅当k = 13*m - 2对于某些 m,13将标记 13*m ± 2

这不会改变标记数量,因这里使用足够大的缓存,运行时间很小,但对小缓存是很重要的。

另外一件事情,你的108的限制太高了。我使用了一个下限( 百万),不高估 100,000的双素数对。第一个变量当然不能按时完成,第二个可以能不是。

在这个条件下,Atkin的筛选需要经过一些优化,以击败Eratosthenes的变体,甚至是 3的数和倍数,这是一个简单的实现,。

关于你的pseudocode的一些注释( wikipedia Atkin筛选器:

#define limit 100000000
int prime1[MAXN];
int prime2[MAXN];

你不需要第二个 array,最大的双对双对可以以很容易地计算出来。你正在浪费空间,并从两个数组中破坏缓存位置读取。( 与筛选所需的时间相比,这是次要的。)

 int root = ceil(sqrt(limit));
 bool sieve[limit];

在许多操作系统上,这是一个即时 segfault,即使有一个减少的限制。堆栈大小通常限制为 8MB 或者更低。应在堆上分配该大小的数组。

如上所述,每个数字使用一个 bool 使程序运行得远远慢于所需的速度。你应该使用 std::bitset 或者 std::vector<bool>,或者自己旋转这些位。建议至少忽略偶数个数字。

 for (int x = 1; x <= root; x++)
 {
 for (int y = 1; y <= root; y++)
 {
//Main part of Sieve of Atkin
 int n = (4*x*x)+(y*y);
 if (n <= limit && (n % 12 == 1 || n % 12 == 5)) sieve[n] ^= true;
 n = (3*x*x)+(y*y);
 if (n <= limit && n % 12 == 7) sieve[n] ^= true;
 n = (3*x*x)-(y*y);
 if (x> y && n <= limit && n % 12 == 11) sieve[n] ^= true;
 }
 }

这种方法效率非常低。它尝试了太多的x-y-combinations,对于每个组合,它执行三到4 个除法,检查余数 12,然后在 array 中来回跳。

分离不同的quadratics 。

对于 4*x^2 + y^2,显然你只需要考虑 x <sqrt(limit)/2 和奇 y然后,余数 12为 1,5或者 9.如果余数是 9,那么 4*x^2 + y^2 实际上是 9的倍数,所以这样一个数字将被消除为不平方自由。然而,最好从筛选器中忽略 3倍的倍数并处理这些情况。n % 12 == 1n % 12 == 5单独。

对于 3*x^2 + y^2,很明显,你只需考虑 x <sqrt(limit/3),一点思考就会显示 x 必须是奇数和 y

对于 3*x^2 - y^2y <x,很明显,你只需考虑 y <sqrt(limit/2)查看模 12的余数,你将看到 y 不能被 3和 x 整除,y 必须具有不同的奇偶性。

原作者:
...