GMOJ3188. 【GDOI2013模擬8】找數
阿新 • • 發佈:2021-10-15
題目大意
找出第 \(n\) 個最小素因子是 \(p\) 的正整數。保證答案 \(\le 10^9\)。
\(n,p\le10^9\)
解題思路
給出一個不用腦子的做法。
根據我們小學二年級就學過的min_25篩,我們可以在 \(O(\frac{n ^ {0.75}}{\log n})\) 對於每一個 \(j\) 得到這個:
其中 \(f(i)\) 是完全積性函式。
你發現用這個就能搞事情。試著做一個差分。
\[g(n,j-1)-g(n,j)=\sum_{i=1}^n[\min_{p|i}p=p_j]-[p_j\le n] \]我們就求出了 \(n\)
可以近似看做是 \(O(n^{0.75})\)的。
#include <cmath> #include <cstdio> #include <cstring> #include <algorithm> #pragma GCC optimize(2) #define fo(i, a, b) for(int i = (a); i <= (b); ++i) const int N = 1e9, M = 32e3; int tot, p[M], c; bool v[M + 5]; void pre() { fo(i, 2, M) { if(!v[i]) p[++c] = i; fo(j, 1, c) { if(p[j] * i > M) break ; v[p[j] * i] = 1; if(!(i % p[j])) break ; } } } int rnk, pr, pj, sq, g[M * 2 + 10], w[M * 2 + 10], id1[M + 10], id2[M + 10]; int getid(int n, int x) {return x <= sq ? id1[x] : id2[n / x];} bool check(int n) { int m = 0; sq = sqrt(n); for(int l = 1, r; l <= n; l = r + 1) { r = n / (n / l), w[++m] = n / l; g[m] = w[m] - 1; w[m] <= sq ? id1[w[m]] = m : id2[n / w[m]] = m; } int res = (pr <= n) + (pj == 1 ? n - 1 : 0); for(int i = 1; i <= pj; ++i) { for(int j = 1; j <= m && p[i] * p[i] <= w[j]; ++j) g[j] -= (g[getid(n, w[j] / p[i])] - (i - 1)); if(i == pj) res -= g[1]; if(i == pj - 1) res += g[1]; } return res >= rnk; } int main() { pre(); scanf("%d %d", &rnk, &pr); pj = c; fo(i, 1, c) if(pr == p[i]) pj = i; int l = 1, r = 1e9, ans = 0, mid; while(l <= r) { mid = (l + r) >> 1; if(check(mid)) r = (ans = mid) - 1; else l = mid + 1; } printf("%d", ans); return 0; }