计算幺半群/半群的所有中缀积

Computing all infix products for a monoid / semigroup

简介:中缀产品组

假设我有一个群组

G = (G, *)

和元素列表

A = {0, 1, ..., n} ⊂ ℕ
x : A -> G

如果我们的目标是实现一个功能

f : A × A -> G

这样

f(i, j) = x(i) * x(i+1) * ... * x(j)

(我们不关心如果 i > j 会发生什么)

然后我们可以通过预先计算 table 个前缀

来做到这一点
m(-1) = 1
m(i) = m(i-1) * x(i)

(右边的1表示G的单位)然后实现f

f(i, j) = m(i-1)⁻¹ * m(j)

之所以有效,是因为

m(i-1) = x(0) * x(1) * ... * x(i-1)
m(j) = x(0) * x(1) * ... * x(i-1) * x(i) * x(i+1) * ... * x(j)

等等

m(i)⁻¹ * m(j) = x(i) * x(i+1) * ... * x(j)

充分重新关联后。

我的问题

如果 G 只是一个幺半群,而不是群?

对于我的特定问题,如果 G = ([0, 1] ⊂ ℝ, *),我们可以做类似的事情吗,即我们有来自单位线的实数,我们不能除以 0 ?

是的,如果 G 是 ([0, 1] ⊂ ℝ, *),那么这个想法可以挽救,使得在 O(log n) 时间(或更准确地说,O( log z) 其中 z 是 A 中 a 的数量,其中 x(a) = 0).

对于每个 i,计算乘积 m(i) = x(0)*x(1)*...*x(i),忽略任何零(因此这些乘积将始终为非零) .此外,为所有零元素构建索引的排序数组 Z。

如果 [i, j] 范围内有零,则 i 到 j 的元素的乘积为 0,否则为 m(j) / m(i-1)。

要查找范围[i, j] 中是否有零,可以在Z 中二分查找Z 中>= i 的最小值,并将其与j 进行比较。这就是额外的 O(log n) 时间成本出现的地方。

一般幺半群解

在 G 是任意幺半群的情况下,可以对 n 个乘积进行预计算,使任意范围的乘积可在 O(log(j-i)) 时间内计算,尽管它比上面更具体的情况有点复杂.

不是预先计算前缀乘积,而是为所有 i、j 计算 m(i, j),其中 j-i+1 = 2^k 对于某些 k>=0,并且 2^k 同时除以 i 和 j。事实上,对于 k=0 我们不需要计算任何东西,因为 m(i, i+1) 的值只是 x(i).

所以我们需要计算n/2 + n/4 + n/8 + ...总产品,最多n-1个东西。

可以从这些构建块(和原始数组的元素)的 O(log_2(j-i+1)) 构造任意区间 [i, j]:选择最大的建筑物包含在区间中的块,并在它的两侧附加大小递减的块,直到到达 [i, j]。然后将每个构建块的预计算乘积 m(x, y) 相乘。

例如,假设您的数组大小为 10。例如,我假设幺半群是自然数的加法。

i: 0  1  2  3  4  5  6  7  8  9
x: 1  3  2  4  2  3  0  8  2  1

2: ----  ----  ----  ----  ----
   4     6     5     8     3

4: ----------- ----------
   10          13

8: ----------------------
   23

此处,第 2、4 和 8 行显示长度为 2、4、8 的对齐间隔的总和(如果数组的长度不是 2 的幂,则忽略剩余的位)。

现在,假设我们要计算 x(1) + x(2) + x(3) + ... + x(8)。

即 x(1) + m(2, 3) + m(4, 7) + x(8) = 3 + 6 + 13 + 2 = 24。