SPOJ PRIME1 : TLE

Я попытался реализовать алгоритм сегментированного сита для этого [вопроса]: http://www.spoj.pl/problems/PRIME1/ следующим образом:

#include <iostream>
#include <string>
#include <set>
#include<math.h>
#include<vector>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cstdio>
#define MAX 32000 // sqrt of the upper range
using namespace std;
int base[MAX];  // 0 indicates prime

vector<int> pv;   // vector of primes

int mod (int a, int b)
{
   if(b < 0)
     return mod(-a, -b);   
   int ret = a % b;
   if(ret < 0)
     ret+=b;
   return ret;
}
void sieve(){

     for(int i = 2 ; i * i < MAX ; i++ )
        if(!base[i])
           for(int j = i * i ; j <  MAX ; j += i )
                 base[j] = 1;

     for(int i = 2 ; i < MAX ; i++ )
         if(!base[i]) pv.push_back(i);

}
int fd_p(int p ,int a ,int b){  // find the first number in the range [a,b] which is divisible by prime p

/*  while(1){

        if(a % p == 0 && a !=p) break;
    a++;
    }
    return a;
*/  

    if(a != p){
        return (a + mod(-a,p)) ;

    }
    else{
     return (a + p);
    }

}
void seg_sieve(int a , int b){

    if(b < 2 ){ 
        cout << "" ;
    return;
    }
    if(a < 2){
      a = 2; 
    }
    int i,j;
    int seg_size  = b - a + 1;
    int*is_prime = new int[seg_size];
    memset(is_prime,0,seg_size*sizeof(int));

    vector<int> :: iterator p ;


    for(p = pv.begin(); p!=pv.end(); p++){
       int x = fd_p(*p,a,b);  

       for(i = x; i <= b; i += *p )
           is_prime[i - a] = 1;
      }

for(i=0; i < b - a + 1; i++)
    if(!is_prime[i])
        printf("%u\n", i + a);

 delete []is_prime ;
}


int main()
{
     sieve();
     int a,b,T;
     scanf("%d",&T);

     while(T--){
     scanf("%d%d",&a,&b);
     seg_sieve(a,b);
     printf("\n");   
     }
//     cout<<endl;
//     system("PAUSE");
     return 0;
}

Тем не менее, я получаю TLE. Я не понимаю, какая еще оптимизация потребуется. Помогите плз..

Редактировать 1: только что попытался реализовать fd_p() за постоянное время... [сбой]... пожалуйста, помогите мне с этой ошибкой...

Редактировать 2: проблема решена.


person spd    schedule 17.08.2012    source источник
comment
См. ‹a href=stackoverflow.com/questions/10249378/›.   -  person user448810    schedule 17.08.2012


Ответы (4)


Вы можете получить первое число в интервале [a,b], которое делится на p за постоянное время. Попробуйте сделать это, и я думаю, вы должны быть готовы идти.

person Ivaylo Strandjev    schedule 17.08.2012
comment
пожалуйста, посмотрите отредактированный код: [концепция] пусть n = a + x будет желаемым числом .. поэтому мы хотим n % p = 0 или (a + x) % p = 0, поэтому [ans = (-a % p) + а] - person spd; 17.08.2012
comment
наконец-то заработало.. Спасибо.. - person spd; 19.08.2012

Я решил эту проблему много лет назад. Предположим, что n-m ‹= 100000 Все, что вам нужно, чтобы вычислить все простые числа от 1 до sqrt(1000000000) ‹ 40000. Затем вручную проверить каждое число от n до m. этого будет достаточно

 program prime1;
  Var
   t:longint;
   m,n:longint;
   i,j,k:longint;
   prime:array of longint;
   bool:boolean;
begin
 SetLength(prime,1);
 prime[0]:=2;
 for i:=3 to 40000
  do begin
   j:=0; bool:=true;
   while (prime[j]*prime[j]<= i ) do begin
     if (i mod prime[j] = 0) then begin
      bool:=false;
      break;
     end;
     inc(j);
   end;
   if (bool) then begin
    SetLength(prime,length(prime)+1);
    prime[length(prime)-1]:=i;
   end;
 end;
 readln(t);
 for k:=1 to t do begin
  readln(m,n);
  for i:=m to n do begin
   if (i=1) then continue;
   j:=0; bool:=true;
   while (prime[j]*prime[j]<= i ) do begin
     if (i mod prime[j] = 0) then begin
      bool:=false;
      break;
     end;
     inc(j);
   end;
   if (bool) then
     writeln(i);
  end;
  writeln;
 end;
end.
person Gloomcore    schedule 17.08.2012

Вам осталось сделать последний шаг к улучшению. Работайте только с коэффициентами.

Мы знаем, что 2 — простое число, и мы знаем, что никакое четное число (кроме 2) никогда не бывает простым. Так что нет необходимости их проверять.

Решето Эратосфена для нечетных простых чисел имеет вид P = {3,5, ...} \ U {{p2< /em>, p2 + 2p, ...} | p в P}. Реализации этого будет достаточно, чтобы пройти через:

  • Относитесь к 2 особо, как к отдельному случаю. Работа с массивами половинного нормального размера, где запись массива по смещению i представляет собой нечетное значение ao + 2*i, где ao = a|1 — наименьшее нечетное число не ниже a. Это означает, что значение приращения 2p соответствует приращению p смещения в массиве.
  • Начальное нечетное число, кратное простому числу p в массиве сита смещения, равному или превышающему p*p, равно m = p*p >= ao ? p*p : ((ao+p-1)/p)*p; m = m&1 ? m : m+p; при условии, что p <= sqrt_b. Соответствующее смещение в массиве сита равно (m-ao)/2.

Кстати, ваше имя сбивает с толку: is_prime на самом деле is_composite.

person Will Ness    schedule 18.08.2012
comment
эй, спасибо, но я получил код, просто заставив функцию fd_p работать в постоянное время .. :) .. нет необходимости рассматривать 2 как отдельный случай .. но я также попытаюсь реализовать ваш метод. - person spd; 19.08.2012

Что не так, так это то, что ваша функция fd_p слишком медленная, увеличение a до тех пор, пока вы не найдете подходящее значение для запуска вашего сита, определенно истечет по времени, поскольку a может быть в диапазоне 1 миллиарда.

Хотя у тебя правильная мысль.

См. этот пост в блоге для более простого понимания объяснения с рабочим кодом:

http://www.swageroo.com/wordpress/spoj-problem-2-prime-generator-prime1/

person Community    schedule 11.09.2012