Humble Numbers丑数
译 by tim green
目录[隐藏] |
[编辑]描述
对于一给定的素数集合 S = {p1, p2, ..., pK},考虑一个正整数集合,该集合中任一元素的质因数全部属于S。这个正整数集合包括,p1、p1*p2、p1*p1、p1*p2*p3...(还有其它)。该集合被称为S集合的“丑数集合”。
注意:我们认为1不是一个丑数。
你的工作是对于输入的集合S去寻找“丑数集合”中的第N个“丑数”。所有答案可以用longint(32位整数)存储。
补充:丑数集合中每个数从小到大排列,每个丑数都是素数集合中的数的乘积,第N个“丑数”就是在能由素数集合中的数相乘得来的(包括它本身)第n小的数。
[编辑]格式
PROGRAM NAME: humble
INPUT FORMAT:
(file humble.in)
第 1 行: 二个被空格分开的整数:K 和 N , 1<= K<=100 , 1<= N<=100,000.
第 2 行: K 个被空格分开的整数:集合S的元素
OUTPUT FORMAT:
(file humble.out)
单独的一行,输出对于输入的S的第N个丑数。
[编辑]SAMPLE INPUT
4 19 2 3 5 7
[编辑]SAMPLE OUTPUT
27
循环队列的使用:
概念上是k个队列,因为因数重复的原因,改为1个队列以节省空间。
相当于每次从k个队列队首取出元素比较,找出最小值,然后将这个(或这些)队列向后扩展。
扩展的规律是:原来队首数可以表示为p*a,新的队首是p*b,则b是比a大而且最小的一个只包含这k个质因数的数。
实现方式是用这个循环队列存储下每次找出的最小值,因此该循环队列保证了单调,下一个因数b一定符合以上要求。则每一个质数用一个指向该队列的指针即可知道下一个因数b的位置。
分析:
一、
因为保证答案在整数范围内,因此理论上需要2^31的空间,即使连续存储不散列存储依然显然不够。
但是分析该例:
2147483648/11 ≈ 195225786
2147483648/13 ≈ 165191049
2147483648/17 ≈ 126322567
2147483648/19 ≈ 113025455
2147483648/23 ≈ 93368854
…………
这些就是不会存入队列中的个数,对于节省空间来说很可观。
二、
然后所有质数的指针位置的极差也会小于一定值,所以可以利用循环队列。
/*
ID: wuyihao1
LANG: C++
TASK: humble
*/
#include <cstdio>
const int inf = 0x7ffffff7;
int p[110];
int top[110];
const int maxq = 2000000;
int que[maxq + 10];
long l = 0;
int main()
{
freopen("humble.in","r",stdin);
freopen("humble.out","w",stdout);
int k;
int n;
scanf("%d%d",&k,&n);
for (int i=1;i<k+1;i++)
{
scanf("%d",p+i);
}
que[0] = 1;
int ans = 0;
for (int i=1;i<n+1;i++)
{
int min = inf;
for (int j=1;j<k+1;j++)
if ((p[j]*que[top[j]]>0) && (p[j]*que[top[j]]) < min)
min = (p[j]*que[top[j]]);
ans = min;
++ l;
if (l == maxq)
l = 0;
que[l] = min;
for (int j=1;j<k+1;j++)
if (que[top[j]]*p[j] == min)
{
top[j] ++;
if (top[j] == maxq)
top[j] = 0;
}
}
printf("%d\n",ans);
return 0;
}