1. 程式人生 > >【BZOJ4524】[Cqoi2016]偽光滑數 堆(模擬搜索)

【BZOJ4524】[Cqoi2016]偽光滑數 堆(模擬搜索)

整數 多少 while i++ size pop truct 滿足 答案

【BZOJ4524】[Cqoi2016]偽光滑數

Description

若一個大於1的整數M的質因數分解有k項,其最大的質因子為Ak,並且滿足Ak^K<=N,Ak<128,我們就稱整數M為N-偽光滑數。現在給出N,求所有整數中,第K大的N-偽光滑數。

Input

只有一行,為用空格隔開的整數N和K 2 ≤ N ≤ 10^18, 1 ≤ K ≤ 800000,保證至少有 K 個滿足要求的數

Output

只有一行,為一個整數,表示答案。

Sample Input

12345 20

Sample Output

9167

題解:先打表打出前31個質數,然後枚舉每個質數作為最大質因子,算出此時最多能有多少項,那麽此時的最大值顯然=這個質數^項數。我們將其扔到堆中。

然後我們要做的就是每次從堆中取出最大的數,將他的一個質因子變小,然後再扔到隊列中去,重復k次。並且我們要保證我們的取法不會出現遺漏和重復。這就是一個套路了。我們試圖模擬搜索的過程。在搜索時,假如我們已經取了一些質數,他們的積為val,那麽我們可以再取一個val的最小質因子,或者繼續考慮下一個更小的質因子。現在我們要模擬這個方法:

我們維護四元組(val,mn,first,second)代表當前的數,最小的質因子編號,最小的質因子次數,次小的質因子次數。那麽如果我們從堆中取出一個數,我們可以用一個最小質因子來換一個次小質因子,或者用最小質因子的下一個質數來替換最小質因子。容易發現這樣是可以做到不重不漏的。由於每次我們只往堆中扔進去2個數,所以時間復雜度就是$O(Klog_K)$的。(看見那些時間復雜度是$O(31*Klog_K)$的我就想笑~)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;
typedef long long ll;
int m;
ll n;
int p[]={1,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};//31
struct node
{
	ll val;
	int mn,lst,sec;
	bool operator < (const node &a) const
	{
		return val<a.val;
	}
};
priority_queue<node> q;
int main()
{
	scanf("%lld%d",&n,&m);
	register node x,y;
	register int i,j;
	for(i=1;i<=31;i++)
	{
		ll tmp;
		for(tmp=1,j=0;tmp<=n/p[i];j++,tmp*=p[i]);
		x.val=tmp,x.mn=i,x.lst=j-1,x.sec=0;
		q.push(x);
	}
	while(--m)
	{
		x=q.top(),q.pop();
		if(x.mn)
		{
			y.val=x.val/p[x.mn]*p[x.mn-1],y.mn=x.mn-1,y.lst=1,y.sec=x.lst-1;
			q.push(y);
		}
		if(x.sec)
		{
			y.val=x.val/p[x.mn+1]*p[x.mn],y.mn=x.mn,y.lst=x.lst+1,y.sec=x.sec-1;
			q.push(y);
		}
	}
	x=q.top();
	printf("%lld",x.val);
	return 0;
}

【BZOJ4524】[Cqoi2016]偽光滑數 堆(模擬搜索)