入门OJ 1126【丑数】

描述

对于一给定的素数集合 S = {p1, p2, ..., pK},如果一个数字,当我们对其做完质因子分解后,其质因子全是来自我们给定的素数集合,则认为这个数字是个丑数。
注意:我们不认为1 是一个丑数。 
你的工作是对于输入的集合S去寻找第N个丑数。

输入输出格式

输入

第 1 行: 二个被空间分开的整数:K 和 N , 1<= K<=100 , 1<= N<=100,000. 
第 2 行: K 个被空间分开的整数:集合S的元素

输出

第N个丑数。.

输入输出样例

输入样例

4 19
2 3 5 7

输出样例

27

解题思路

  首先想到的就是一个一个慢慢计算上去,但是肯定会超时,果断放弃,然后用了队列,每次取出队头,然后一个一个乘集合里的数,但是发现这个没按大小顺序排列,所以又WA了。然后,一种很神奇的东西——优先队列出现了:

  优先队列是经过一系列玄学的操作,让优先级高的先出列

  priority_queue<int> q;通过操作,按照元素从大到小的顺序出队

  priority_queue<int,vector<int>, greater<int> > q;通过操作,按照元素从小到大的顺序出队

  本题果断选第二种。注意,这里不再用q.front()而是用q.top()取队首元素。

  然后呢,你就会发现,2*3和3*2重复了,这可怎么办呢?打标记吗?但是我嫌太麻烦,聪明的我果断选择了另一种方式:

  那么我们推一推可能会发现,我们让每一个取出的元素乘质数时从小到大,如果取出的元素%这个质数=0,那么就乘完这个质数就不继续向后乘了(因为某个质数的k次方也是丑数,所以要放进去)。每一个存进去的数字,都是从小到大乘过来的,就可以避免重复,于是可以优化一个logn的复杂度。最后在循环到第n次时,取出来的便是第n小的,即第n个丑数。

题解

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n,k,ans; 
 4 int s[10001];//存集合 
 5 priority_queue<long long, vector<long long>, greater<long long> > q;//优先队列 
 6 int main()
 7 {    
 8     cin>>n>>k;//我把n和k反着存的 
 9     for(int i=1;i<=n;i++)
10     {
11         cin>>s[i];    
12         q.push(s[i]);//进队列 
13     }
14     for(int i=1;i<=k;i++)
15     {
16         long long head=q.top();//取队头 
17         q.pop();//弹出 
18         if(i==k)cout<<head;//第k小就输出 
19         for(int j=1;j<=n;j++)
20         {
21             q.push(head*s[j]);//进队列 
22             if(head%s[j]==0)//去重 
23             break;
24         }
25     }
26     return 0;
27 }
原文地址:https://www.cnblogs.com/hualian/p/11184679.html