gpt4 book ai didi

c++ - SPOJ 问题 KPRIMES2

转载 作者:可可西里 更新时间:2023-11-01 17:59:00 26 4
gpt4 key购买 nike

我是这个论坛的新手,不太了解这个论坛的协议(protocol),所以请原谅我的无知。我的问题与spoj问题有关https://www.spoj.pl/problems/KPRIMES2/ .对于这个问题,我遇到了 TIME LIMIT EXCEED。我认为这个程序的瓶颈是生成 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() 函数生成素数,我将素数编码到数字位 [32 位无符号整数] 上。 bitcnt 数组存储数组 a 的未设置位的总和,用于二进制搜索目的。bsearchupper(int m) 返回 m 所在的 bitcnt 的索引。最后在 main 函数中,我存储了多少个素数达到 m 的上限并开始递减值直到我得到 K。谢谢。

编辑:来自 SPOJ 的问题陈述

输入

一个整数,表示查询的数量 Q(等于 100000),后面是 Q 行,每行包含一个介于 1 和 50000000 之间的整数 K。

输出

Q 行包含每个查询的答案:第 K 个素数。

例子

输入:8个1个10100100010000100000100000010000000

输出:2个295417919104729129970915485863179424673

#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;
}

最佳答案

考虑进一步压缩您的主要存储空间。例如,在2*3*5*7*11=2310的每一 block 中,恰好有1*2*4*6*10=480个没有11以下质因数的数,你可以将其打包成15数组条目而不是(大约)36。这将消除筛选出那些小因素的几亿位操作。您必须将索引更改为位数组;几个长度为 2310 的常量数组给出位索引(如果它存在)和数组元素偏移量在这里会有所帮助,一个类似的数组(长度为 480)将位位置转换回值 mod 2310。

关于c++ - SPOJ 问题 KPRIMES2,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4825169/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com