【问题标题】:SPOJ PRIME1 : TLE [closed]SPOJ PRIME1:TLE [关闭]
【发布时间】:2012-08-17 09:58:02
【问题描述】:

我尝试为这个[问题]实现分段筛算法: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:问题已解决。

【问题讨论】:

标签: c++ algorithm primes sieve-of-eratosthenes sieve


【解决方案1】:

你可以得到区间 [a,b] 中第一个在常数时间内能被 p 整除的数。尝试这样做,我认为你应该很好。

【讨论】:

  • 请查看编辑后的代码:[概念] 让 n = a + x 成为所需的数字.. 所以我们想要 n % p = 0 或 (a + x) % p = 0 所以 [ans = (-a % p ) + a]
  • 终于让它工作了..谢谢..
【解决方案2】:

多年前我已经解决了这个问题。假设,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.

【讨论】:

    【解决方案3】:

    您还剩下最后一步需要改进。 只处理赔率。

    我们知道2 是素数,而且我们知道没有偶数(除了 2)是素数。所以没有必要检查它们。

    奇数素数的埃拉托色尼筛是 P = {3,5, ...} \ U {{p2 sup>, p2 + 2p, ...} | p 在 P} 中。实施这将足以让你通过:

    • 特别对待2,作为一个单独的案例。使用正常大小一半的数组,其中偏移量i 处的数组条目表示奇数值ao + 2*i,其中ao = a|1 是不低于a 的最小奇数。这意味着 2p 的增量值对应于数组中偏移量 p 的增量。李>
    • 偏移筛阵列中素数p 的起始奇数倍数等于或大于p*p,是m = p*p &gt;= ao ? p*p : ((ao+p-1)/p)*p; m = m&amp;1 ? m : m+p;,前提是p &lt;= sqrt_b。筛数组中对应的偏移量为(m-ao)/2

    附带说明一下,您的命名令人困惑:is_prime 实际上是 is_composite

    【讨论】:

    • 嘿,谢谢,但我通过让 fd_p 函数在恒定时间内运行来接受代码 .. :) .. 无需将 2 视为单独的案例.. 但我会尝试实现你方法也是。
    【解决方案4】:

    问题是你的 fd_p 函数太慢了,增加 a 直到你找到一个好的值来启动你的筛子肯定会超时,因为 a 可以在 10 亿的范围内。

    不过你的想法是对的。

    请参阅此博客文章,以获得更易于理解的工作代码解释:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-04-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多