1. 程式人生 > 其它 >GMOJ3188. 【GDOI2013模擬8】找數

GMOJ3188. 【GDOI2013模擬8】找數

題目大意

找出第 \(n\) 個最小素因子是 \(p\) 的正整數。保證答案 \(\le 10^9\)

\(n,p\le10^9\)

解題思路

給出一個不用腦子的做法。
根據我們小學二年級就學過的min_25篩,我們可以在 \(O(\frac{n ^ {0.75}}{\log n})\) 對於每一個 \(j\) 得到這個:

\[g(n,j)=\sum_{i=1}^n[i \in Prime\ |\ \min_{p|i}p>p_j]f(i) \]

其中 \(f(i)\) 是完全積性函式。

你發現用這個就能搞事情。試著做一個差分。

\[g(n,j-1)-g(n,j)=\sum_{i=1}^n[\min_{p|i}p=p_j]-[p_j\le n] \]

我們就求出了 \(n\)

以內最小素因子是 \(p\) 的數的個數。你發現二分一下 \(n\) 就做完了。 注意特判 \(j=1\) 的情況。

可以近似看做是 \(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;
}