题目描述
对于一给定的素数集合 S=P1,P2,...,Pk考虑一个正整数集合,该集合中任一元素的质因数全部属于 S 。这个正整数集合包括,P1 、P1×P1 、P1×P2 、P1×P2×P3 ...(还有其它)。该集合被称为 S 集合的“丑数集合”。注意:我们认为 1 不是一个丑数。
你的工作是对于输入的集合 S 去寻找“丑数集合”中的第 n 个“丑数”。
补充:丑数集合中每个数从小到大排列,每个丑数都是素数集合中的数的乘积,第 n 个“丑数”就是在能由素数集合中的数相乘得来的(包括它本身)第 n 小的数。
输入格式
输入的第一行是两个的整数,分别代表集合 S 的大小 k 和给定的参数 n
输入的第二行有 K 互不相同的整数,第 i 个整数代表 Pi
输出格式
输出一行一个整数,代表答案
样例输入
4 19
2 3 5 7
样例输出
27
思考:
观察题目,我们不难得到以下结论:
- 每一个丑数,都是从已经有的丑数中迭代而来(初始给的素数集视为特殊情况)
- 每个丑数迭代的k个丑数中,我们仅需要优先考虑未出现的其中的最小值
倘若将每一个丑数分别乘以Pi后再比较,时间复杂度与空间复杂度无疑是巨大的,但是由结论2我们可以找到一个未出现的丑数Ui*Pi,其中Ui,Pi均只考虑一次,且应尽可能小,为了找到最小值,我们不妨以Pi作为基准,找到已有丑数中未与Pi相乘过的最小值。
如:给定的素数集2,3,5
已经计算得到的丑数为
2,3,4,5,6,8,9,10,12
对于2:2*2=4,2*3=6,2*5=10均已出现,不予考虑
对于3:3*2=6、3*3=9已出现,3*5=15,考虑15
对于4:4*2=8、4*3=12已出现,4*5=20,虽然20还未出现,但是计算对应的P3=5已经与更小的3相乘,故不予考虑
对于6:6*2=12已出现,6*3=18,考虑18
对于8:8*2=16,考虑16
由此我们得到了比较集:15,16,18,其中的最小值15即为下一个丑数
代码实现:
不妨设U[0]=1作为基准丑数,U[ i ]表示第i个丑数,我们以素数集合为2,3,5,7为例,设Pt1,Pt2,Pt3,Pt4,初始值均为0,考虑U[ Pt1 ]*2,U[ Pt2 ]*3,U[ Pt3 ]*5,U[ Pt4 ]*7中的最小值,找到最小值U[ Pti ]*Pi后,其对应Pti+1,表示U[ Pti ]已经与Pi相乘过了,下一次比较时不再考虑,而下一个未与Pi相乘过的最小丑数为U[ Pti + 1 ],如果有多个值相同的情况,则相应Pti均+1,表示得到最小值相同的情况,如2*3与3*2所得丑数是一样的
拓展到给定素数集合有k个元素的情况,我们有:
首先计算比较集合:c[ k ]
void getMatrix()
{
for (int i = 0; i < numOfPrime; i++)
{
c[i] = u[Pt[i]] * P[i];
}
}
进行比较,返回最小值(即下一个丑数)同时对应标记Pti进位
long long getMin()
{
long long tmp = c[0];
for (int i = 1; i < numOfPrime; i++)
{
tmp = tmp < c[i] ? tmp : c[i];
}
for (int i = 0; i < numOfPrime; i++)//numOfPrime为素数集合中元素的个数
{
if (tmp == c[i]) Pt[i]++;
}
return tmp;
}
求第n个丑数:
long long getUgly()
{
for (int i = 1; i < target; i++)
{
getMatrix();
u[i] = getMin();
}
return u[target - 1];
}
完整代码如下:
#include<iostream>
using namespace std;
class ugly
{
public:
int numOfPrime;
int target;
long long* u;
long long* P;
long long* c;
long long* Pt;
ugly(int x,int y)
{
numOfPrime = x;
target = y + 1;
c = new long long[numOfPrime];
u = new long long[target] { 1 };
Pt = new long long[numOfPrime] {0};
P = new long long[numOfPrime];
for (int i = 0; i < numOfPrime; i++)
{
cin >> P[i];
}
}
long long getMin()
{
long long tmp = c[0];
for (int i = 1; i < numOfPrime; i++)
{
tmp = tmp < c[i] ? tmp : c[i];
}
for (int i = 0; i < numOfPrime; i++)
{
if (tmp == c[i]) Pt[i]++;
}
return tmp;
}
void getMatrix()
{
for (int i = 0; i < numOfPrime; i++)
{
c[i] = u[Pt[i]] * P[i];
}
}
long long getUgly()
{
for (int i = 1; i < target; i++)
{
getMatrix();
u[i] = getMin();
//cout << u[i] << " ";(得到完整的丑数列,观察一下是否正确,不在题目要求内)
}
return u[target - 1];
}
};
int main()
{
int k, n;
cin >> k >> n;
ugly UglyNumber(k, n);
cout<<UglyNumber.getUgly();
return 0;
}
输出结果为(包含完整丑数序列):