SPOJ 问题 KPRIMES2
我是这个论坛的新手,不太了解这个论坛的协议,所以请原谅我的无知。我的问题与 spoj 问题有关 https://www.spoj.pl/problems/KPRIMES2/。我遇到这个问题的时间限制超出。我认为这个程序的瓶颈是生成 10^9。有人可以建议如何改进这个筛子,更快地生成素数的方法或如何解决这个问题。这是我的算法的草图
该程序生成 2k+1 形式的所有素数,并将这些素数编码为数组 a[i] 的 32 位整数,其中未设置的位表示素数。a[0] 编码 3,5,7.. .....65.a[1] 编码 67 及以上,依此类推。我采用了一个辅助数组 bitcnt[] ,其中 bitcnt[i] 存储 a[0], a[1],.........a[i] 的未设置位的总和。我使用bitcnt进行二分查找并找到第k个数字的位置。这里是函数的位解释。 prime() 函数生成素数,并将素数编码到 number[32 位无符号整数] 的位上。 bitcnt 数组存储数组 a 的未设置位的总和,用于二分搜索。 bsearchupper(int m) 返回 m 所在的 bitcnt 的索引。 最后在主函数中,我存储了有多少素数达到 m 的上限,并开始减小值,直到得到 K。谢谢。
的问题陈述
编辑:来自 SPOJ输入
一个整数,说明查询数量 Q(等于 100000),后面是 Q 行,每行包含一个介于 1 到 50000000 之间的整数 K(含)。
输出
Q 行,其中包含每个查询的答案:第 K 个素数。
输入示例
: 8 1 10 100 1000 10000 100000 1000000 10000000
输出: 2 29 第541章 7919 104729 1299709 15485863 179424673
#include<cstdio>
#include<vector>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<ctime>
#define Lim 1000000000
using namespace std;
unsigned int a[(Lim>>6)+10],bitcnt[(Lim>>6)+10];
int bound;
void prime()
{
int p_1,q_1,p_2,q_2,Ub=sqrt(Lim*1.0);
for(int i=3;i<=Ub;i+=2)
{
p_1=(i-3)>>6,q_1=((i-3)>>1)&31;
if(!(a[p_1] & (1L<<q_1)))
for(int j=i*i;j<Lim;j+=i)
if(j&1)
{
p_2=(j-3)>>6,q_2=((j-3)>>1)&31;
a[p_2]|=(1L<<q_2);
}
}
int cnt=0;bound=0;
for(int i=0; i<=((Lim>>6)-1);i++)
{
//p_1=(i-3)>>6,q_1=((i-3)>>1)&31;
cnt+=__builtin_popcount(~a[i]);
bitcnt[bound++]=cnt;
//cout<<bound-1<<"---"<<bitcnt[bound-1]<<endl;
}
//cout<<cnt<<endl;
}
int bsearchupper(int m)
{
int lo=0,hi=bound,mid;
while(lo<hi)
{
mid=lo+((hi-lo)>>1);
if(bitcnt[mid]<=m)lo=mid+1;
else hi=mid;
}
//cout<<"lo= "<<lo<<" mid= "<<mid<<" hi= "<<hi<<endl;
return lo;
}
int main()
{
//clock_t start,end;
//start=clock();
prime();
int t,k,c,ret,w;
for(scanf("%d",&t);t>0;t--)
{
scanf("%d",&k);
if(k==1) {cout<<"2"<<endl;continue;}
k=k-2;
c=bsearchupper(k);
ret=bitcnt[c],w=32*(c+1);
for(int i=31;i>=0;i--)
{
if(!(a[c] & (1L<<i)))
{
ret--;
if(ret==k) printf("%d\n",3+(w-1)*2);
}
w--;
}
}
//end=clock();
//cout<<((end-start)/(double)CLOCKS_PER_SEC)<<endl;
}
I am new to this forum and not well aware of protocols of this forum so pardon me for my ignorance. My question is related to spoj problem https://www.spoj.pl/problems/KPRIMES2/. I am getting TIME LIMIT EXCEED for this problem.I think the bottleneck of this program is generating 10^9.Could some one suggest how to improve this sieve , faster way to generate prime or how to solve this problem. Here is sketch of my algorithm
This program generates all the primes of form 2k+1 and encoded these primes into 32 bit integers of array a[i] in which unset bit represents primes.a[0] encodes 3,5,7.......65.a[1] encodes 67 onwards and so on. I have taken a auxiliary array bitcnt[] , in which bitcnt[i] stores sum of unset bits of a[0], a[1],.........a[i]. I used bitcnt for binary search and find the position of kth number.Here is bit explanation of functions.
prime() function generated primes and i encoded the primes onto bits of number[32 bit unsigned integer]. bitcnt array stores sum of unset bits of array a for binary search purpose.
bsearchupper(int m) return index of bitcnt in which m lie.
Finally in main function , i am storing how many primes are upto upperbound of m and started decreasing value till i got K. Thank you.
Edit:Problem statement from SPOJ
Input
An integer stating the number of queries Q(equal to 100000), and Q lines follow, each containing one integer K between 1 and 50000000 inclusive.
Output
Q lines with the answer of each query: the Kth prime number.
Example
Input:
8
1
10
100
1000
10000
100000
1000000
10000000
Output:
2
29
541
7919
104729
1299709
15485863
179424673
#include<cstdio>
#include<vector>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<ctime>
#define Lim 1000000000
using namespace std;
unsigned int a[(Lim>>6)+10],bitcnt[(Lim>>6)+10];
int bound;
void prime()
{
int p_1,q_1,p_2,q_2,Ub=sqrt(Lim*1.0);
for(int i=3;i<=Ub;i+=2)
{
p_1=(i-3)>>6,q_1=((i-3)>>1)&31;
if(!(a[p_1] & (1L<<q_1)))
for(int j=i*i;j<Lim;j+=i)
if(j&1)
{
p_2=(j-3)>>6,q_2=((j-3)>>1)&31;
a[p_2]|=(1L<<q_2);
}
}
int cnt=0;bound=0;
for(int i=0; i<=((Lim>>6)-1);i++)
{
//p_1=(i-3)>>6,q_1=((i-3)>>1)&31;
cnt+=__builtin_popcount(~a[i]);
bitcnt[bound++]=cnt;
//cout<<bound-1<<"---"<<bitcnt[bound-1]<<endl;
}
//cout<<cnt<<endl;
}
int bsearchupper(int m)
{
int lo=0,hi=bound,mid;
while(lo<hi)
{
mid=lo+((hi-lo)>>1);
if(bitcnt[mid]<=m)lo=mid+1;
else hi=mid;
}
//cout<<"lo= "<<lo<<" mid= "<<mid<<" hi= "<<hi<<endl;
return lo;
}
int main()
{
//clock_t start,end;
//start=clock();
prime();
int t,k,c,ret,w;
for(scanf("%d",&t);t>0;t--)
{
scanf("%d",&k);
if(k==1) {cout<<"2"<<endl;continue;}
k=k-2;
c=bsearchupper(k);
ret=bitcnt[c],w=32*(c+1);
for(int i=31;i>=0;i--)
{
if(!(a[c] & (1L<<i)))
{
ret--;
if(ret==k) printf("%d\n",3+(w-1)*2);
}
w--;
}
}
//end=clock();
//cout<<((end-start)/(double)CLOCKS_PER_SEC)<<endl;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
考虑进一步压缩您的主要存储。例如,在 2*3*5*7*11=2310 的每个块中,正好有 1*2*4*6*10=480 个数字不具有 11 或更少的质因数,您可以将其打包为 15数组条目而不是(大约)36 个。这将消除筛选出这些小因素的几亿位操作。您必须更改位数组的索引;几个长度为 2310 的常量数组给出位索引(如果存在)和数组元素偏移量在这里会有所帮助,并且一个类似的数组(长度为 480)将位位置转换回模 2310 的值。
Consider compacting your prime storage even more. For example, in every block of 2*3*5*7*11=2310, there are exactly 1*2*4*6*10=480 numbers that have no prime factor of 11 or less, which you can pack into 15 array entries rather than (about) 36. That will eliminate a few hundred million bit operations sieving out those small factors. You'll have to change your indexing into the bit array; a couple of constant arrays of length 2310 giving the bit index (if it exists) and array element offset would help here, and a similar array (of length 480) converting bit positions back into values mod 2310.