64位的各位对应值的哈希表,这是一个为了能够有效单独处理每一位所对应的一个数据。由于一共有64位,二进制各位模64,从第7位开始就全为0了,故首先从65看,而65不冲突的个数仅为12个,66不冲突的个数仅为11个。但计算到67时,会发现,刚好所有二进制单位上的值模67全部无冲突。即有64个不重复的数字。这些数字可以构建一个2的幂的哈希表,使得所有查询,修改,删除全为O(1)O(1)O(1)
因此采用 hash(n)=n mod 67\text{hash}(n)=n\ \text{mod}\ 67hash(n)=n mod 67 即可构建无冲突的二的幂的哈希表。对一些进制函数的处理非常有用,二进制在各种组合dfs中总会碰到的,可以考虑这样的hashmap。
示例













或许你以为到这就完了,但实际上,稍微想想,能找到一些数论的关系出来。

原根定义,若gi≡1(mod n)g^i\equiv1\left(\text{mod}\ n\right)gi≡1(mod n)的最小正整数i=φ(n)i=\varphi(n)i=φ(n)称ggg为nnn的原根。
很显然,哈希表的函数要的是2作为哪个大于等于最大长度的数的原根。如这里是找到大于等于64的原根。设mmm为定义域长度,即最高要达到的aia^iai的iii的最大值为mmm。则φ(n)≥m\varphi(n)\ge mφ(n)≥m 且 nnn是aaa的原根。

最好的结果是直接考虑nnn为素数的情况,nnn是素数下。φ(n)=n−1≥m\varphi(n)=n-1\ge mφ(n)=n−1≥m,需从m+1m+1m+1开始考虑。考虑大于mmm的素数,检测其是否具备222作为其原根的特性。不过光这个也都无法有固定公式,因为2是否是无穷多个素数的原根的问题本来就未被证明的,它来自于埃米尔阿廷猜想。当然不会有固定的公式。但是就一般的ACM题或者工程需要,不超过64的范围内都没有什么特别的需要处理的。

可以用Mathematica来查询:

SelectFirst[Select[Prime[Range[k]], # > m &], PrimitiveRoot[#] == 2 &]

表示大于m的在前k个素数中找到原根为2的n。这个数就是构建哈希表模的数。输入k=100和m=64可得67恰为答案。
对于m=128来说,k取100可得131为哈希表长。

mk值
32100037
64100067
1281000131
2561000269
5121000523
102410001061

还有一种方法查询,但是是大概率不会查到最小一个满足的:

FindInstance[Prime[n] > m && PrimitiveRoot[Prime[n]] == 2, n, Integers, k]

其中获得的是第n个素数的n,需要自行选取内部的n。当m特别大时采用。
这里讨论的东西可以完全扩展到其他底数的单幂值的哈希表,不只是2还可以有3,5等等。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐