【SSLGZ 1648】丑数

问题描述
对于一给定的素数集合 S = {p1, p2, …, pK}, 来考虑那些质因数全部属于S 的数的集合。这个集合包括,p1, p1p2, p1p1, 和 p1p2p3 (还有其它)。这是个对于一个输入的S的丑数集合。
  注意:我们不认为1 是一个丑数。
  你的工作是对于输入的集合S去寻找集合中的第N个丑数。longint(signed 32-bit)对于程序是足够的。
输入
第 1 行: 二个被空格分开的整数:K 和 N , 1<= K<=100 , 1<= N<=100,000.
第 2 行: K 个被空格分开的整数:集合S的元素
输出
单独的一行,写上对于输入的S的第N个丑数。
样例输入
4 19
2 3 5 7
样例输出
27
算法讨论
丑数就是因子在S集合里的数,那么我们就先将1放入数组,构建堆,然后拿堆里最小的数去乘S集合里的数放入数组,每次乘完就插入小顶堆中,注意去重。最后到n+1是乘出来的数就是第n大的丑数。

const
  maxn=300000;
var
  a:array[1..maxn] of longint;
  b:array[1..100] of longint;
  i,j,n,k,l:longint;
  t:int64;

procedure siftup(i:longint);
var
  t:longint;
begin
  if i=1
    then exit;
  while i>1 do
    begin
      if a[i]div 2]
        then begin
               t:=a[i];
               a[i]:=a[i div 2];
               a[i div 2]:=t
             end
        else break;
      i:=i div 2
    end;
end;

procedure siftdown(i:longint);
var
  t:longint;
begin
  if i*2>l
    then exit;
  while i*2<=l do
    begin
      i:=i*2;
      if (i+1<=l) and (a[i+1]then i:=i+1;
      if a[i div 2]>a[i]
        then begin
               t:=a[i];
               a[i]:=a[i div 2];
               a[i div 2]:=t
             end
        else break
    end;
end;

procedure insert(i:longint);
begin
  inc(l);
  a[l]:=i;
  siftup(l)
end;

procedure delete(i:longint);
var
  x,y:longint;
begin
  x:=a[i];
  y:=a[l];
  dec(l);
  if i=l+1
    then exit;
  a[i]:=y;
  if y>=x
    then siftdown(i)
    else siftup(i)
end;

begin
  read(k,n);
  for i:=1 to k do
    read(b[i]);
  a[1]:=1;
  l:=1;
  for i:=1 to n+1 do
    begin
      t:=a[1];
      for j:=1 to k do
        if t*b[j]then insert(t*b[j]);
      delete(1);
      while a[1]=t do
        delete(1)
    end;
  write(t)
end.

【SSLGZ 1648】丑数_第1张图片
Pixiv ID:58623537

你可能感兴趣的:(堆)