[数据结构][usaco3.1.3]Humble Numbers

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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值