[CQOI2016]伪光滑数

[CQOI2016]伪光滑数

洛谷题目链接

莫名其妙的一道与素数相关的题


题目大意

我们需要求\(N\)​​的第\(K\)​​大的伪光滑数,对于伪光滑数的定义,我们将一个数\(M\)​​分解成\(k\)​​个质因数,其中最大的质因子\(a(a<128)\)​​,当\(a^k<=N\)​​时我们才称\(M\)​是\(N\)​的伪光滑数。


思路

首先我们必须要注意到所有的质因子\(a<=128\)​,所以我们可以提前求出所有的\(a\)​,也就是打表。很明显的我们可以想到枚举所有的质因子求出所有的伪光滑数,但是很显然一定会\(T\)​,但是我们观察到\(K\)​是比较小的,所以,我们只需要求\(K...N\)​的伪随机数。


解释

我们需要先求出所有\(a^k<=N,k\in Z,a<128\)​将它们加到大根堆中,然后取\(K\)​​​​​次。取完一个数\(x\)​时,我们需要看这个数的次数是否大于一,如果是,则加入所有\(x\div x最大的质因子 \times 第i个质数,如果最大的质因子是第m个,则i<m\),所以我们用一个结构体维护这个堆,注意为了使str库中的堆可以用,必须重载运算符

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll N,K;
int p[]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127};
struct node{
	ll val;int maxp,k,r;
	friend bool operator <(node a,node b){
		return a.val<b.val;
	}
};
priority_queue<node>q;
int main(){
	//freopen("smooth.in","r",stdin);
	//freopen("smooth.out","w",stdout);
	scanf("%lld%lld",&N,&K);
	for(int i=1;i<=31;++i){
		ll sum=p[i];
		for(int j=1;sum<=N;++j,sum*=p[i]){
			q.push((node){sum,p[i],j,i-1});
		}
	}
	while(K--){
		node x=q.top();
		q.pop();
		if(K==0){
			printf("%lld\n",x.val);
			return 0;
		}
		if(x.k>1){
			for(int i=1;i<=x.r;++i){
				q.push((node){x.val/x.maxp*p[i],x.maxp,x.k-1,i});
			}
		}
	}
	return 0;
}
posted @ 2021-08-19 17:39  fanner_rick  阅读(104)  评论(0)    收藏  举报