Smooth
考场\(AC\),还是很开心的。
考虑这题让你干啥,就是给你一堆素数,然后让你用他们去构造数,求其中第\(k\)小的。
我们可以用系数累乘的方式,同时利用小根堆实现有序,加一个优化,就过了。
首先将所有已有的素数丢进堆,然后每次取堆顶,取出来后扫描给出的素数,将它与这些素数的积丢进堆,重复过程直到有\(k\)个数已被取出过。
有一个优化,就是参考了欧拉筛的思路,当当前的堆顶%当前枚举到的素数为0是就跳出,可以保证每个数只被构造一次。
考场上被\(STL\)的堆卡常了,只有90分,靠。
代码:
Code
//2000ms
//512MB
#include<bits/stdc++.h>
using namespace std;
namespace STD
{
#define rr register
typedef long long ll;
const int K=1e7+4;
const ll N=1e18+2;
int k,b,cnt;
int prime[30];
ll line[K];
bool is_not_prime[105];
ll read()
{
rr ll x_read=0,y_read=1;
rr char c_read=getchar();
while(c_read<'0'||c_read>'9')
{
if(c_read=='-') y_read=-1;
c_read=getchar();
}
while(c_read>='0'&&c_read<='9')
{
x_read=(x_read<<3)+(x_read<<1)+(c_read^48);
c_read=getchar();
}
return x_read*y_read;
}
void pre()
{
for(rr int i=2;i<=100;i++)
{
if(!is_not_prime[i]) prime[++cnt]=i;
for(rr int j=1;j<=cnt&&prime[j]*i<=100;j++)
{
is_not_prime[i*prime[j]]=1;
if(!(i%prime[j])) break;
}
}
}
class Heap
{
private:
int tot;
ll heap[K<<1];
void up(int);void down(int);
void swap(ll &x,ll &y){x^=y,y^=x,x^=y;}
public:
Heap(){tot=0;}
void push(ll val){heap[++tot]=val;up(tot);}
void pop(){heap[1]=heap[tot--];down(1);}
inline ll top(){return heap[1];}
}heap;
void Heap::up(int p)
{
while(p>1)
{
if(heap[p]<heap[p>>1])
{
swap(heap[p],heap[p>>1]);
p>>=1;
}
else break;
}
}
void Heap::down(int p)
{
int s=p<<1;
while(s<=tot)
{
if(s<tot&&heap[s]>heap[s+1]) s++;
if(heap[s]<heap[p])
{
swap(heap[s],heap[p]);
p=s,s=p<<1;
}
else break;
}
}
};
using namespace STD;
int main()
{
//priority_queue<ll,vector<ll>,greater<ll> > heap;
pre();
b=read(),k=read();
for(rr int i=1;i<=b;i++) heap.push(prime[i]);
while(1)
{
rr ll x=heap.top();
heap.pop();
line[++line[0]]=x;
if(line[0]==k-1) break;
for(rr int i=1;i<=b;i++)
{
heap.push(x*prime[i]);
if(x%prime[i]==0) break;
}
}
printf("%lld\n",line[line[0]]);
}