SPOJ Задача KPRIMES2

Я новичок на этом форуме и не очень хорошо знаком с протоколами этого форума, так что извините меня за мое невежество. Мой вопрос связан с проблемой spoj https://www.spoj.pl/problems/KPRIMES2/. Я получаю ПРЕВЫШЕНИЕ ВРЕМЕНИ для этой проблемы. Я думаю, что узкое место этой программы генерирует 10 ^ 9. Может ли кто-нибудь предложить, как улучшить это сито, более быстрый способ генерировать простое число или как решить эту проблему. Вот набросок моего алгоритма

Эта программа генерирует все простые числа формы 2k+1 и кодирует эти простые числа в 32-битные целые числа массива a[i], в котором неустановленный бит представляет собой простые числа. 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) возвращает индекс bitcnt, в котором лежит m. Наконец, в основной функции я сохраняю количество простых чисел до верхней границы m и начинаю уменьшать значение, пока не получу K. Спасибо.

Изменить: Постановка задачи от SPOJ

Вход

Целое число, указывающее количество запросов Q (равное 100000), и следующие за ним Q строк, каждая из которых содержит одно целое число K от 1 до 50000000 включительно.

Вывод

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

person keep_learning    schedule 28.01.2011    source источник
comment
Один совет, ориентированный на протокол, который я бы дал, состоит в том, чтобы обобщить достаточно проблемы, которую вы пытаетесь решить, что (например), если SPOJ окажется в автономном режиме, когда кто-то читает это, они все равно смогут понять, что вы пытаетесь решить. пытаясь сделать.   -  person Jerry Coffin    schedule 28.01.2011


Ответы (1)


Подумайте о том, чтобы еще больше сжать основное хранилище. Например, в каждом блоке 2*3*5*7*11=2310 есть ровно 1*2*4*6*10=480 чисел, не имеющих простого делителя 11 или меньше, которые можно упаковать в 15. записей массива, а не (около) 36. Это устранит несколько сотен миллионов битовых операций, отсеивающих эти небольшие факторы. Вам придется изменить индексацию на битовый массив; здесь поможет пара постоянных массивов длиной 2310, дающих битовый индекс (если он существует) и смещение элемента массива, и аналогичный массив (длиной 480), преобразующий битовые позиции обратно в значения по модулю 2310.

person Chris Nash    schedule 22.02.2011