快速应答子阵查询的有效算法

时间:2017-08-01 23:59:50

标签: c++ algorithm

前几天我遇到了与查询相关的问题,但我无法解决。

给定具有 N 整数和正整数 M 的数组,您必须回答 Q 查询。每个查询的特征为( i j ),其中 i j 是数组的每个索引。在每个查询中,您必须回答存在多少对( r s ),以便

  1. i < = r < = s < = j
  2. [ r s ]中索引的数组元素之和可被M整除。
  3. 限制:

    N <= 50,000
    Q <= 50,000
    M <= 100
    

    我有一个动态编程解决方案,可以预处理O( N ^ 2)中的每个查询( r s ),但这是不够快。有更有效的解决方案吗?我对Mo的算法或段树有一些想法,但我无法得到它。

2 个答案:

答案 0 :(得分:3)

  1. 计算每个i = 1..N的原始数组的前缀总和(假设它基于1)。
    enter image description here
    任何两个索引Sum[r]Sum[s]的{​​{1}}和r的等效性,其中s表示索引位于{{1}的数组元素的总和可以被r < s整除(我们需要计算区间内这种等价的数量)。此步骤的时间复杂度为[r+1, s]

  2. 为每个M预先计算数组O(N)enter image description here
    Count存储i = 1..N, j = 0..M-1Count[i][j])等于Sum[len]的次数。此步骤的时间复杂度为len <= i

  3. 对于每个查询j,答案将等于: enter image description here
    对于余数O(N*M)的每个可能值,我们找到(i, j) - kD(k)区间内等于Sum[len]的次数。然后,我们向结果中添加k[i, j]区间边界的所有可能对的数量D(k)。时间复杂度:每个查询D(k)*(D(k)-1)/2

  4. 复杂性O(M),对于给定的约束条件就可以了。

答案 1 :(得分:1)

首先请注意,对于任何总和为(r, s)倍数的子阵列M

sum(r, s) == sum(i, s) - sum(i, r - 1)

          == (qa * M + ra) - (qb * M + rb)

其中rarb都小于M且大于或等于0除以后的相应余​​数M)。

现在sum(r, s)可以被M整除,因此在除以0之后,其余为M。因此:

ra == rb

如果我们在将子数组(i, i)(i, i + 1),...,(i, j)除以M作为r1之后,将所有余数计算出来,{ {1}},...,r2然后将所有这些的计数存储在大小为rj的数组R中,以便M为剩余数量等于R[k],然后:

k

并且对于每个R[0] == the number of subarrays starting at i that are divisible by M k >= 0k < M我们可以计算R[k] > 1选择R[k]

2

不从(R[k] * (R[k] - 1)) / 2 开始且可被{​​{1}}整除的子阵列。

创建和求和所有这些值为我们提供了每个i查询的O(N + M)答案。