其他分享
首页 > 其他分享> > 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;
}

标签:10,min,找数,GMOJ3188,mid,int,ans,include,GDOI2013
来源: https://www.cnblogs.com/Martin-MHT/p/15386153.html