问题
I tried implementing the segmented sieve algorithm for this [question]:http://www.spoj.pl/problems/PRIME1/ as follows :
#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;
}
I am getting TLE nevertheless .. I don't understand what other optimization would be required . Plz help ..
Edit 1 :just tried to implement fd_p() in constant time ... [failure] .. plz if u could help me with this bug..
Edit 2:Issue Resolved.
回答1:
You can get the first number in the interval [a,b] that is divisible by p in constant time. Try to do that and I think you should be good to go.
回答2:
I have solved this problem many years ago. Assume, that n-m <= 100000 All you need to calculate all Primes between 1 and sqrt(1000000000) < 40000. Than manually test each number between n and m. This will be ehough
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.
回答3:
You've left one last step of improvement to make. Work with the odds only.
We know that 2
is prime, and we know that no even (other than 2) is ever a prime. So there's no need to check them.
The sieve of Eratosthenes for odd primes is P = {3,5, ...} \ U {{p2, p2 + 2p, ...} | p in P}. Implementing that will be enough to get you through:
- Treat
2
specially, as a separate case. Work with arrays half the normal size, where the array entry at offseti
represents an odd valueao + 2*i
whereao = a|1
is the least odd number not belowa
. That means that increment value of 2p corresponds to the increment of p in the offset in the array. - The starting odd multiple of a prime
p
in the offset sieve array, equal to or abovep*p
, ism = p*p >= ao ? p*p : ((ao+p-1)/p)*p; m = m&1 ? m : m+p;
, provided thatp <= sqrt_b
. The corresponding offset in the sieve array is(m-ao)/2
.
As a side note, your naming is confusing: is_prime
is actually is_composite
.
回答4:
What's wrong is that your fd_p function is far too slow, incrementing a till you find a good value to start your sieve will definitely time out since a can be in the range of 1 billion.
You have the right idea though.
See this blog post for an easier to understand explanation with working code as well:
http://www.swageroo.com/wordpress/spoj-problem-2-prime-generator-prime1/
来源:https://stackoverflow.com/questions/12003616/spoj-prime1-tle