1. 程式人生 > >藍橋杯 演算法提高 找素數 【思維找素數 + 篩法】

藍橋杯 演算法提高 找素數 【思維找素數 + 篩法】

時間限制:1.0s 記憶體限制:256.0MB

問題描述

  給定區間[L, R] , 請計算區間中素數的個數。

輸入格式

  兩個數L和R。

輸出格式

  一行,區間中素數的個數。

樣例輸入

2 11

樣例輸出

5

資料規模和約定

  2 <= L <= R <= 2147483647 R-L <= 1000000

題意: 略

分析: 知道一般的素數篩法的應該都知道原理,這裡其實就是模擬一下那裡的篩法,簡敘如下:

  • 1.預處理出[0,2147483647]內的所有素數
  • 2.用[0,r - l]來表示[l,r],找到對應關係
  • 3.利用篩法的思想進行篩數,比如第一個素數 2,[l,l+2]
    其中肯定有一個是2的倍數,找到起點,然後往後掃一遍篩掉即可
  • 4.考慮3的做法是否合理,因為 r - l的範圍是1e6,時限上過不去的,考慮優化,我們可以想到其實我們可以在O(1)的時間內找到起點,只有幾種情況:

    • <1> 當素數p >= l, 我們只需將起點放在 p - l處即可
    • <2> 否則,考慮l % p是否為0,如若為0,則就在0點,否則在 p - l % p
    • <3> 如果當前起點 + l為素數時,就要往後走p個單位

    ●5.O(n)統計可以

參考程式碼

#include <bits/stdc++.h>

using namespace
std; const int maxn = 1e6 + 7; int m = (int) sqrt(2147483647+0.5) + 10; bool isp[maxn]; int p[maxn/10]; int len; void init() { isp[0] = isp[1] = true; for (int i = 2; i < m; i++) { if (!isp[i]) p[++len] = i; for (int j = 1; j <= len && p[j]*i < m; j++) { isp[i*p[j]] = true
; if(i % p[j] == 0) break; } } } int main() { init(); memset(isp,false,sizeof isp); int l,r;cin>>l>>r; int Len = r - l + 1; for (int i = 1; i <= len; i++) { int L; if(p[i] >= l) L = p[i] - l; else { if(l % p[i] == 0) L = 0; else L = p[i] - l%p[i]; } if(l + L == p[i]) L += p[i]; for (int j = L; j <= Len; j += p[i]) { isp[j] = true; } } int cnt = 0; for(int i = 0; i < Len; i++) { if (!isp[i]) cnt++; } if(l == 1) cnt--; cout<<cnt<<endl; return 0; }
  • 如有錯誤或遺漏,請私聊下UP,thx