[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;
}