1. 程式人生 > >【JZOJ5458】質數【數論,數學】

【JZOJ5458】質數【數論,數學】

題目大意:

LLRR中是質數或是兩個質數之積的數的個數。

思路:

首先,觀察最大資料: LR107,Q105L\leq R\leq 10^7,Q\leq 10^5 那麼肯定是要離線做的。 肯定是要先篩質數,那麼就用線性篩,不僅得到11RR之間的質數,還得到了每個數的最小質因數 那麼對於一個數xx

  • 如果它是質數,那麼就很明顯ans++ans++

  • 如果它不是質數:

    • 我們知道了這個數的最小質因數v[x]v[x],那麼如果它符合題目的要求就必然有x=prime[i]×prime[j]x=prime[i]\times prime[j]。我們又知道v[x]xv[x]|x且是質數,所以說,如果要符合題意,就有x=v[x]×prime[j]x=v[x]\times prime[j],即prime[j]=x÷v[x]prime[j]=x\div v[x]。所以說,如果x÷v[x]x\div v[x]是質數,那麼就ans++ans++
    • 否則不合法。

那麼我們可以求出字首和sss[i]s[i]表示11RR中間有多少符合要求的數。然後O(1)O(1)回答即可。 時間複雜度:O

(107)O(10^7)(固定值,其實是O(R)O(R)

程式碼:

#include <cstdio>
#include <cstring>
#define N 10000100
#define MAXN 10000000
#define ll long long
using namespace std;

int sum,v[N],prime[N],s[N],l,r,n;
bool isp[N];

int f;
char c;

int read()  //輸入流
{
	c=getchar();
	f=0;
	while (c<'0'||c>'9') c=getchar
(); while (c>='0'&&c<='9') { f=f*10+(c-'0'); c=getchar(); } return f; } int write(int x) //輸出流 { if (x>9) write(x/10); putchar(x%10+48); } void find() { for (int i=2;i<=MAXN;i++) //線性篩 { if (!v[i]) { v[i]=i; prime[++sum]=i; isp[i]=1; } for (int j=1;j<=sum;j++) { if (prime[j]>MAXN/i) break; if (prime[j]>v[i]) break; v[i*prime[j]]=prime[j]; } } for (int i=2;i<=MAXN;i++) if (isp[i]||isp[i/v[i]]) //符合要求 s[i]=s[i-1]+1; else s[i]=s[i-1]; } int main() { find(); n=read(); while (n--) { l=read(); r=read(); write(s[r]-s[l-1]); putchar(10); } return 0; }