1. 程式人生 > >bzoj4524 [Cqoi2016]偽光滑數 堆

bzoj4524 [Cqoi2016]偽光滑數 堆

Description

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

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

Solution

有點無聊的題

我們列舉最大質數,貪心地把合法的最大質數的次冪扔進堆裡。每次取堆頂然後去掉一個質因數,乘上一個次小的質因數即可 這大概不是正解。不過50多行價效比很高了

Code

#include <stdio.h>
#include <string.h>
#include <set> #define rep(i,st,ed) for (register int i=st;i<=ed;++i) typedef long long LL; const int N=20005; std:: set <LL> set; bool not_prime[N]; int prime[N],cnt; int read() { int x=0,v=1; char ch=getchar(); for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar()); for (
;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar()); return x*v; } void pre_work(int n) { prime[0]=1; rep(i,2,n) { if (!not_prime[i]) prime[++cnt]=i; for (int j=1;i*prime[j]<=n&&j<=cnt;++j) { not_prime[i*prime[j]]=1; if (i%prime[j]==0) break; } } } int main(void) {
LL n,k; scanf("%lld%lld",&n,&k); pre_work(128); rep(i,1,cnt) { for (LL x=prime[i];x<=n;x*=prime[i]) { set.insert(x); } } for (;--k;) { LL s=*set.rbegin(); set.erase(s); rep(i,1,cnt) if (s%prime[i]==0) { set.insert(s/prime[i]*prime[i-1]); } } printf("%lld\n", *set.rbegin()); return 0; }