BZOJ 4524(贪心+二叉堆)

题面

若一个大于 11 的整数M分解质因数后到的有重复的质因数序列有k 项,其最大的质因子为 \(a_k\),并且满足 \({a_k}^k \leq N,k<128\),我们就称整数 M 为 N-伪光滑数。

现在给出 N*N,求所有整数中,第 K大的 N-伪光滑数。

分析

先筛出128以内的所有质数

根据题意贪心考虑,显然M的质因数分解中最大的质数越大越好

于是我们把每个质数p的1次方,2次方,3次方...k次方(\(p^k \leq n\))加入堆(堆顶元素最大).

然后取k-1次,每次对于取出来的数x,除掉它的最大质因子,乘上一个次大的质因子,这样就构造出了一个更小的数,且它显然是 N-伪光滑数

取完k-1次后的堆顶就是最大的质数了

用优先队列模拟这个过程,由于优先队列中的元素可能会重复,会影响结果(重复的数被取出多次,导致取出来的不是第k大的),我们只要一次取出所有的最大元素即可

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<set>
#include<queue>
#define maxn 1005
using namespace std;
long long n;
int k;

int cnt=0;
int vis[maxn];
int prime[maxn];
void sieve(int n){
	for(int i=2;i<=n;i++){
		if(!vis[i]){
			prime[++cnt]=i;
		}
		for(int j=1;j<=cnt&&i*prime[j]<=n;j++){
			vis[i*prime[j]]=1;
			if(i%prime[j]==0) break;
		}
	}
}

priority_queue<long long>q;
int main(){
	scanf("%lld %d",&n,&k);
	sieve(128);
	for(int i=1;i<=cnt;i++){
		for(long long x=prime[i];x<=n;x*=prime[i]){
			q.push(x);
		}
	}
	for(int i=1;i<=k-1;i++){
		long long x=q.top();
		while(!q.empty()&&x==q.top()) q.pop();
		long long y;
		for(int i=1;i<=cnt;i++){
			if(x%prime[i]==0){
				y=x/prime[i]*prime[i-1];
				q.push(y);
			}
		}
	}
	printf("%lld\n",q.top());
}
posted @ 2019-03-20 22:02  birchtree  阅读(135)  评论(0编辑  收藏  举报