素数判断及筛法

单个素数判断
//素数判断(小数据)
int prime(int n) {
    if (n == 0 || n == 1)  return 0;
    if (n == 2)  return 1;
    if (n % 2 == 0) return 0;
    for (int i = 3; i * i <= n; i = i + 2)
        if (n % i == 0)  return 0;
    return 1;
}


//Miller-Rabin(大素数判定) 单个数字n复杂度15*log(n)
int Mr[30] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37};
//此数组为测试用的a,这12个可测所有的long long int;
LLI Miller_Rabin(LLI n) {
    if(n == 2)               return true;
    else if(n < 2)          return false;
    if(n % 2 == 0)          return false;
    LLI u = n - 1;
    while(u % 2 == 0)   u = u / 2;
    LLI  tempu = u;
    for(int i = 0; i < 12; i ++) {
        if(Mr[i] >= n)  break;
        u = tempu;
        LLI x = Fast_power(Mr[i],u,n);//这里调用快速幂函数,p18
        while(u < n) {
            LLI y = (x % n) * (x % n) % n;
            //注意!!!(x % n) * (x % n)很可能溢出,如果出现这种情况,用快速乘
            //另外调用快速幂时也可能溢出
            if(y == 1 && x != 1 && x != n - 1)  return false;
            x = y;
            u = u * 2;
        }
        if(x != 1)  return false;
    }
    return true;
}
区间素数筛

//厄拉多塞素数筛法,复杂度>O(n*log(log(n)))
bool mark[maxn];
void sieve_prime() {
    memset(mark, true, sizeof(mark));
    mark[0] = mark[1] = false;
    for (int i = 2; i * i <= maxn; i ++)
        if (mark[i])
            for (int j = i * i; j < maxn; j = j + i)
                mark[j] = false;
}
//欧拉素数筛法复杂度O(n)
bool isPrime[maxn];
LLI primeList[maxn],primeCount = 0;
void Eular_Sieve(LLI n) {
    memset(isPrime,true,sizeof(isPrime));
    isPrime[0] = false;
    isPrime[1] = false;
    for(int i = 2; i <= n; i ++) {
        if(isPrime[i]) {
            primeCount ++;
            primeList[primeCount] = i;
        }
        for(int j = 1; j <= primeCount; j ++) {
            if(i * primeList[j] > n)    break;
            isPrime[i * primeList[j]] = false;
            if(!(i % primeList[j]))    break;
        }
    }
}


素数筛法的应用
题目链接: Help Hanzo

题意就是求[a,b]区间内的素数个数( 1 ≤ a ≤ b < 231, b - a ≤ 100000);
很明显,如果直接筛肯定不行……,见代码:

#include 
      
      
       
       
#include 
       
       
#include 
        
        
         
         
#include 
         
         
          
          
#include 
          
          
            #include 
           
             #include 
            
              #include 
             
               #include 
              
                #include 
               
                 #include 
                
                  #include 
                 
                   #include 
                  
                    #include 
                   
                     #include 
                    
                      #include 
                     
                       #include 
                      
                        #include 
                       
                         #define pi acos(-1.0) #define maxn (500000 + 5) #define mol 1000000000 + 7 #define Lowbit(x) (x & (-x)) using namespace std; typedef long long int LLI; bool flag[100000 + 20]; bool isPrime[maxn]; LLI primeList[maxn],primeCount = 0; void Eular_Sieve(LLI n) { memset(isPrime,true,sizeof(isPrime)); isPrime[0] = false; isPrime[1] = false; for(int i = 2; i <= n; i ++) { if(isPrime[i]) { primeCount ++; primeList[primeCount] = i; } for(int j = 1; j <= primeCount; j ++) { if(i * primeList[j] > n) break; isPrime[i * primeList[j]] = false; if(!(i % primeList[j])) break; } } } int main() { // freopen("in.txt","r",stdin); // freopen("out.txt","w",stdout); Eular_Sieve(maxn); int t; scanf("%d",&t); for(int Case = 1; Case <= t; Case ++) { int l,r,n,cnt = 0; memset(flag,true,sizeof(flag)); scanf("%d%d",&l,&r); if(l == 1) l ++; n = r - l; for(int i = 1; i <= primeCount && primeList[i] * primeList[i] <= r; i ++) { int j = 0; if(l % primeList[i] != 0) j = primeList[i] - l % primeList[i]; if(l <= primeList[i]) j += primeList[i]; for(; j <= n; j += primeList[i]) flag[j] = false; } for(int i = 0;i <= n;i ++) if(flag[i]) cnt ++; printf("Case %d: %d\n",Case,cnt); } return 0; } 
                        
                       
                      
                     
                    
                   
                  
                 
                
               
              
             
            
          
         
         
        
        
      
      



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值