最小值为2 ^ l所需的整数形式

时间:2013-10-26 21:59:36

标签: arrays algorithm bits

我今天遇到了这个问题,在这里我们按升序给出了一个排序数组a[],然后我们找到了数字2a1, 2a2, 2a3, ..., 2an的总和,我们需要找到最小的附加数量类型为2ll的非负数)的整数必须是必需的,以使得所有整数的总和等于2k - 1对于某个整数k({{ 1}}是非负的。)

例如:

输入由第一行中的整数n组成。第二个输入行包含n个以空格分隔的整数a(1),a(2),...,a(n)。

示例1:
3
0 1 2

这个案例的答案是0,因为2 0 +2 1 +2 2 = 7已经是2 < sup> k -1,k = 3。

例2:
3
2 4 5

这个案例的答案是3,因为2 2 +2 4 +2 5 = 52并使其成为2 k -1我们有63个所以需要2 0 ,2 1 ,2 3 作为三个术语。

我找到了这个问题来找到总和,然后计算二进制表示中的1的数量,然后回答等于k

但我得到的问题是问题中的给定约束 1≤n≤10^ 5
0≤a[i]≤2* 10 ^ 9

有人可以帮忙吗? 我在编程竞赛和2.6 MB内存中接受的解决方案中遇到了这个问题。 因此,存储或获取2 * 10 ^ 9位的数组位并不会更好。我认为会有不同的方法或想法。

2 个答案:

答案 0 :(得分:3)

您不需要2 * 10 ^ 9位内存来解决此问题。 n(n <10 ^ 5)上的边界表明了另一种解决方案:

(1)对a_i

进行排序

3 3 3 3 3 5 7 9

(2)通过二进制搜索找到连续副本,摆脱重复。在这种情况下,您有5(二进制为=101),因此3 3 3 3 3变为3 5。您的a_i现在是3 5 5 7 9。 (请注意,这相当于以二进制形式添加数字,但它更高效,因为您知道您的数字最多有10 ^ 9位,但最多设置为10 ^ 5位!)

(3)重复步骤2,直到不再有重复项。在此示例中,您只需要另一个步骤,最后得到3 6 7 9

(4)计算max(a_i) - number of a_i left + 1。这是您的结果,在本例中为9-4+1=6


步骤(2)的可能实施:

我要尝试的第一件事就是从头开始覆盖,但保留一个指针来检查我现在的位置,所以:你读了3。您二进制搜索最后3并保留指向以下元素的指针。然后,您覆盖:3 3 3 3 3 5 7 9 - &gt; 3 5 x x x *5 7 9x位置的内容并不重要,指针现在位于5。现在,对于第一个解决方案,只需从末尾复制所有内容,使其再次连续:3 5 5 7 9并记住您的数组现在更短。

这是不是最有效的解决方案,因为如果你有像3 3 4 4 5 5 6 6...这样的数组会导致很多复制,但它应该足够好。

为了获得更好的性能,您只能执行步骤(1),然后将所有内容插入到将a_i映射到其显示次数的哈希映射中,然后对该哈希映射进行操作。这对于你的约束非常快,但在C中实现一个hashmap并不是一件容易的事。

答案 1 :(得分:0)

您需要做的是使用位数组。

您需要 i &lt; = 2 * 10 9 (20亿)。要表示20亿位,您需要大约256MB的内存(每个字节存储8位)。您可能需要创建一些方便的抽象层,它将提供.get(int n).set(int n)等函数,这些函数将读取并保存该位数组中的位。


要分配数组,请使用malloc

typedef byte unsigned char;
// 256MB, enough for 2 billion bits
byte * bit_array = malloc(256*1024*1024);

// or use calloc, which initializes to 0:
byte * bit_array = calloc(256*1024*1024, 1);

要设置位n,请使用以下分配:

bit_array[n/8] |= 1 << (n % 8);

要获得位n,请使用以下表达式:

(bit_array[n/8] >> (n % 8)) & 1

你的算法可能是这样的:

  • 创建所需的最大长度的位数组。
  • 遍历所有 i 并将该位数组中的第i位设置为0.
  • 计算仍然设置为1的位数。这是你的答案。