BitwiseAnd

作者:马龙 徐明宽

关键词:位运算 贪心 字典序

题目简述

给定一个正整数集合与正整数,你要构造出一个包含个元素的新正整数集合,使其包含该给定的集合为子集,每个元素均不超过,且满足下列条件:

  • 对于集合中的任意两个不同元素
  • 对于集合中的任意三个不同元素

其中,是二进制下的按位与运算。假如满足要求的集合不存在,输出空集;否则,假如有多个解,输出将元素排序后字典序最小的一个。

中的元素不超过

分析

我们首先来考虑“字典序最小”这一要求。不难发现,假如我们能最小化所有不在中的元素里的最小值,其次最小化次小值,以此类推,就能得到字典序最小的方案:考虑将这个方案与另外一个比较字典序,与这一最小值相比较的数假如在中,就一定会比它大;假如不在,由于它是最小值,也不会比对方更大,因此是最优的。

通过这一观察,我们发现最优策略应当是每次加入一个最小的可能的元素,重复直到集合大小为。考虑加入的元素应满足什么条件。通过题目中的两个限制,我们不难发现,每个数二进制表示中的每个,都不能在超过两个数字中出现,同时每两个数之间也必须存在至少一个公共位。考虑到“最小”的限制,显然让每两个数之间有且仅有一个公共位是最优的。

算法一

经过上面的分析,算法的框架已经十分清晰了。我们可以检查给定的集合中的元素间是否满足要求,然后去除中的元素间的所有公共位;加入新元素时,先构造该元素与中每个元素间的公共位,并把对应的位在中删除,然后用还未出现过的位构造新元素间的所有公共位。假如在任何一步中找不到任何满足要求的位,那么无解,否则就构造出了字典序最小的方案。

复杂度是

优化

为了方便描述复杂度,记中元素的最大值的二进制位数为,则有。可以发现我们至少需要个二进制位,所以有——换句话说,我们可以用的时间把的规模缩小到

我们可以花的时间计算出中元素间两两的公共位,并把它们(斜体字均指位运算)起来,则存在中的三个元素的非0当且仅当在这过程中存在某次之前两个值的非0。

接下来,构造新元素与中每个元素间的公共位时可以使用的时间内完成,构造新元素间的所有公共位也可以这样做。这部分的时间复杂度为

最后,由于给定的和新构造的元素均有序,可以在的时间复杂度内归并排序。

综上,总时间复杂度为

results matching ""

    No results matching ""