提前感谢!
(6*k-1, 6*k+1)
,如果k
没有产生双胞胎素数对,你也不需要知道这两个数字中哪一个是合数,只需要筛选索引k
即可。通过减少限制,Atkin筛选器需要进行一些优化才能打败省略偶数和3的倍数的Eratosthenes变体,一个天真的实现将明显更慢。
#define limit 100000000
int prime1[MAXN];
int prime2[MAXN];
int root = ceil(sqrt(limit));
bool sieve[limit];
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;
}
}
4*x^2 + y^2
,很明显只需要考虑x < sqrt(limit)/2
和奇数的y
,然后余数模12是1、5或9。如果余数为9,则4*x^2 + y^2
实际上是9的倍数,因此这样的数字会被排除为非平方自由数。然而,最好完全省略筛法中的3的倍数,并单独处理n % 12 == 1
和n % 12 == 5
的情况。3*x^2 + y^2
,很明显只需要考虑x < sqrt(limit/3)
,稍加思考就会发现x
必须是奇数,y
必须是偶数(且不能被3整除)。3*x^2 - y^2
,其中 y < x
,很明显你只需要考虑 y < sqrt(limit/2)
。观察模 12 的余数,可以发现 y
不能被 3 整除,而且 x
和 y
必须有不同的奇偶性。基本上,根据 Wolfram Alpha 的说法,筛选到 20,000,000 就足够了。在 C++ 中使用 Eratosthenes 算法筛选奇数,使用 vector<bool>
。 (顺便问一下,你用的是什么语言?)
在筛选循环中跟踪孪生素数。当您找到孪生素数时,在单独的向量中存储一对中较小的素数,并且如果请求一个无序(比先前的索引小)的索引(尽管与描述页面上显示的示例相反),只需从此存储获取素数即可:
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秒内获得接受(在Ideone上为0.18秒)。或者解开逻辑 - 直接预先计算100,000个孪生素数对,然后在单独的循环中访问它们(0.94秒)。
这里有一个程序可以回答你的问题:
当被3整除时,其商在小数点后第一位为0的质数对称为孪生质数。
这可以写成:
对于任意一对质数Px、Py,如果[ Px/3, 0 ] = [ Py/3, 0 ],那么Px和Py就是孪生质数。
这个基础是,如果两个质数相差2,那么将所有感兴趣的质数除以3将产生唯一的相等商,当商被修正为小数点后第一位为0时。不相差2的质数将不会在小数点后第一位为0时具有相等的商。
例如:
• 当11、13被3整除时,将产生唯一的商4,当商被修正为小数点后第一位为0时。
• 当17、19被3整除时,将产生唯一的商6,当商被修正为小数点后第一位为0时。
• 当29、31被3整除时,将产生唯一的商10,当商被修正为小数点后第一位为0时。
等等。
以下是使用Excel执行以下操作的简单过程:要找到最大的孪生质数,请使用上述过程,并将已知最大质数的范围输入到第一列中(例如,最高的10k个质数)。
如果在此范围内未找到孪生质数,则继续查找下一个较低的范围,直到找到孪生质数为止。这将是最大的孪生质数。
希望这可以帮助您。
我使用埃拉托斯特尼筛法预先计算了一大堆质数,然后遍历列表,计算其后继项减2的项目数量,直到找到n个为止。在http://ideone.com/vYjuC上运行时间为1.42秒。我也想知道如何在零秒内计算出答案。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ISBITSET(x, i) (( x[i>>3] & (1<<(i&7)) ) != 0)
#define SETBIT(x, i) x[i>>3] |= (1<<(i&7));
#define CLEARBIT(x, i) x[i>>3] &= (1<<(i&7)) ^ 0xFF;
typedef struct list {
int data;
struct list *next;
} List;
List *insert(int data, List *next)
{
List *new;
new = malloc(sizeof(List));
new->data = data;
new->next = next;
return new;
}
List *reverse(List *list) {
List *new = NULL;
List *next;
while (list != NULL)
{
next = list->next;
list->next = new;
new = list;
list = next;
}
return new;
}
int length(List *xs)
{
int len = 0;
while (xs != NULL)
{
len += 1;
xs = xs->next;
}
return len;
}
List *primes(int n)
{
int m = (n-1) / 2;
char b[m/8+1];
int i = 0;
int p = 3;
List *ps = NULL;
int j;
ps = insert(2, ps);
memset(b, 255, sizeof(b));
while (p*p < n)
{
if (ISBITSET(b,i))
{
ps = insert(p, ps);
j = (p*p - 3) / 2;
while (j < m)
{
CLEARBIT(b, j);
j += p;
}
}
i += 1; p += 2;
}
while (i < m)
{
if (ISBITSET(b,i))
{
ps = insert(p, ps);
}
i += 1; p += 2;
}
return reverse(ps);
}
int nth_twin(int n, List *ps)
{
while (ps->next != NULL)
{
if (n == 0)
{
return ps->data - 1;
}
if (ps->next->data - ps->data == 2)
{
--n;
}
ps = ps->next;
}
return 0;
}
int main(int argc, char *argv[])
{
List *ps = primes(100000000);
printf("%d\n", nth_twin(100000, ps));
return 0;
}
0.0s
的条目是一个 bug。顺便说一下,Ideone 比 SPOJ 快大约 5.5 倍。我们可以以某种方式在源代码中存储预计算的双胞胎,但最少需要 100,000 字节,并且源代码的大小限制为 50K。我想知道这需要多少空间,例如作为哈夫曼编码字符串,这样是否还有足够的空间在源代码中放置解码器? - Will Ness这是我尝试过的。我有一串TLE字符串。
bool mark [N];
vector <int> primeList;
void sieve ()
{
memset (mark, true, sizeof (mark));
mark [0] = mark [1] = false;
for ( int i = 4; i < N; i += 2 )
mark [i] = false;
for ( int i = 3; i * i <= N; i++ )
{
if ( mark [i] )
{
for ( int j = i * i; j < N; j += 2 * i )
mark [j] = false;
}
}
primeList.clear ();
primeList.push_back (2);
for ( int i = 3; i < N; i += 2 )
{
if ( mark [i] )
primeList.push_back (i);
}
//printf ("%d\n", primeList.size ());
}
int main ()
{
sieve ();
vector <int> twinPrime;
for ( size_t i = 1; i < primeList.size (); i++ )
{
if ( primeList [i] - primeList [i - 1] == 2 )
twinPrime.push_back (primeList [i - 1]);
}
int t;
scanf("%d",&t);
int s;
while ( t-- )
{
scanf("%d",&s);
printf ("%d %d\n", twinPrime [s - 1], twinPrime [s - 1] + 2);
}
return 0;
}
vector<bool> mark; mark.resize(N+1,true);
,它是自动位筛(内存大小的1/8)。不要标记偶数,也不要从中读取。不要构建primesList
,而是直接在循环中使用prev_prime
辅助变量构建twinprimes
。希望这样可以在2秒内运行。如果不能,请使用以下技巧:将mark
数组中的第i
个条目视为代表数字i
而不是2i+1
。您的数组将缩小一半。这就是我所做的,它在SPOJ上运行了1.0秒。 - Will Ness
n
个孪生素数的闭式公式,我们将知道它们的数量是有限还是无限。这本身可能值得一枚菲尔兹奖。 - biziclop