我有两个序列:
1.无符号64位数k
的倍数,例如k=5
:{0, 5, 10, 15, 20, 25, ...}
- 64位掩码
m
加上64位常量C
的子集,例如m=0b1011
:{C+0, C+1, C+2, C+3, C+8, C+9, C+10, C+11}
。注:C
与m
不相交,也就是(m & C) = 0
。
除了检查k
的每一个倍数并检查它是否匹配第二个序列标准,或者检查掩码m
的每个子集并与C
进行“或”运算,并与k
进行除法运算之外,还有其他方法可以枚举这两个序列的所有交集吗?
64位数P
位于这两个序列的交集中,如果P % k == 0
和(P & C) == C
和(P & ~(C | m)) = 0
。
注意:枚举第二个序列实际上很容易:
uint64_t m = ..., C = ...;
uint64_t subset = 0;
do {
uint64_t value = subset + C;
print(value);
// if (value % 5) => in the intersection of the sequences
subset = (subset - m) & m;
} while (subset != 0);
编辑:枚举的顺序无关紧要
另外:我并不希望把它们都列举出来,但我希望有某种迭代器,我可以总是前进并获得下一个交集
2条答案
按热度按时间gtlvzcf81#
C mod k
是一个常数,这意味着我们正在寻找m
的子集,这些子集实现了一个且只有一个值modk
-当与C mod k
相加时为零modk
。作为2的幂的
m
的每个比特也是常数modk
。因此,任务似乎是枚举那些总和为x
mod k的组合。例如,对于每个看到的组合,通过将当前2的幂添加到
m
modk
中来生成新的组合。一个直接的优化可以是将2的幂分组在m
中,这些幂等于modk
。除此之外,我不知道有什么技巧可以加快这种搜索速度--组合状态的数量modk
可以取决于k
和m
。1rhkuytd2#
当前的问题是生成一个给定数
k
的倍数的数,并且满足由两个64位常数m
和C
定义的按位准则。如果我们用素因子来考虑这个问题,那么我们要寻找的数字是那些以
k
作为因子的数字,并且其按位表示与给定掩码对齐。如果我们有无穷多个这样的数,它们将均匀分布在数线上,每个数之间的间隔为k
。假设
k=5
,m=0b1011
和C=0
。那么k
的倍数是{0, 5, 10, 15, 20, 25, ...}
,掩码m
加上C
的子集是{0, 1, 2, 3, 8, 9, 10, 11}
。两个序列中的数字都是{0, 5, 10}
。这里是一个建议的解决方案,它利用逐位操作和基本循环来递增地生成序列中的下一个数字。
在此实现中,
IntersectionGenerator::next()
将返回满足条件的下一个数字。while
循环将继续进行,直到找到一个k
的倍数并满足按位标准的数字。当找到这样一个数字时,它将被返回,并计算m
的下一个子集。如果数字不满足条件,则循环继续到下一个子集,并递增k
的当前倍数。该解决方案基于您对类似迭代器的结构的请求,并使用增量计算两个序列交集的方法。如果
k
相对于m
的子集的大小较小,则这将有效地工作。如果
m
的子集的集合更大,这将变得低效,因为它需要针对m
的所有子集测试k
的所有倍数。有n
个元素的集合有2^n
个子集,所以随着m
的大小增加,找到交集所需的迭代次数也会增加。如果序列非常大,则更有效的解决方案将是预先计算并存储序列,然后应用集合交集算法来找到公共元素。但是,这将需要大量内存,并且不会提供您正在寻找的“迭代器”样式的接口。