A-第N個質數
阿新 • • 發佈:2020-07-20
求第n個質數
\(n<= 1e9\)
首先在\(0~1e7\)範圍內的質數我們可以直接尤拉篩解決
但是第\(1e9\)個的質數是\(2e10\)級別的
我們考慮二分答案
然後我們要實現的操作就是求\(1~n\)之間有多少質數,然後二分。
接著我們想一想,一個質數\(x\),它的判定就是不能被\(2 - \sqrt(x)\)之間任何一個數整除,這等價於不能被\(2 - \sqrt(x)\)之間任何一個質數整除
同時我們之前預處理的尤拉篩恰好已經幫我們找出了這些質數
於是乎開始DP
\(g[i][j]\)表示前\(i\)個數中,不能被前\(j\)個質數整除的數的數量
遞推:\(g[i][j] = g[i][j - 1] - g[i / p[j]][j - 1]\)
考慮優化:
- \(j = 0\),\(return \ i\)
- \(i \leq N\), N 是預處理的上界,我們記錄\(f[i]\)表示\(1~i\)之間的質數個數,
\(f[i] \leq j\) , \(return \ 1\)
\(f[\sqrt(i)] \leq j\), \(return f[i] - j + 1\), 表示\(1~i\)之間的每一個合數都能被整除,只剩下所有質數和1, 然後我們減去前\(j\)個質數
以上
#include<bits/stdc++.h> using namespace std; const int N = 8000000; int prime[N/10],cnt; int p[N + 5]; int f[N + 5]; #define int long long int n; int g(int x,int y){ if(x <= 1) return x; if(y == 0) return x; if(y == 1) return x - x/2; if(x <= prime[y]) return 1; if(x <= N){ if(f[x] <= y) return 1; if(f[(int)(sqrt(x))] <= y) return f[x] - y + 1; } return g(x,y - 1) - g(x/prime[y],y - 1); } int check(int d){ int q = sqrt(d); return f[q] + g(d,f[q]) - 1; } signed main(){ p[0] = p[1] = 1; f[0] = f[1] = 0; for(int i = 2; i <= N; ++ i){ f[i] = f[i - 1]; if(!p[i]) prime[++ cnt] = i, ++ f[i]; for(int j = 1; prime[j] * i <= N; ++ j){ p[prime[j] * i] = 1; if(i % prime[j] == 0) break; } } scanf("%lld",&n); if(n <= cnt) { printf("%d\n",prime[n]); return 0; } int l = N + 1, r = 23000000000ll, ans = -1; while(l <= r){ int mid = (l + r) >> 1; int s = check(mid); //printf("%lld %lld\n",mid,s); if(s >= n) { ans = mid; r = mid - 1; } else l = mid + 1; } printf("%lld\n",ans); return 0; }