连续子串和的整除问题

131 阅读4分钟

问题描述

小M是一个五年级的小学生,今天他学习了整除的知识,想通过一些练习来巩固自己的理解。他写下了一个长度为 n 的正整数序列 a_0, a_1, ..., a_{n-1},然后想知道有多少个连续子序列的和能够被一个给定的正整数 b 整除。你能帮小M解决这个问题吗?


测试样例

样例1:

输入:n = 3,b = 3,sequence = [1, 2, 3]
输出:3

样例2:

输入:n = 4,b = 5,sequence = [5, 10, 15, 20]
输出:10

样例3:

输入:n = 5,b = 2,sequence = [1, 2, 3, 4, 5]
输出:6

连续子序列的和通常使用前缀和处理

问题理解

我们需要计算一个长度为 n 的正整数序列中,有多少个连续子序列的和能够被一个给定的正整数 b 整除。

数据结构的选择

  1. 前缀和数组

    • 前缀和数组 prefix_sum 记录了从序列开始到每个位置的和。
    • prefix_sum[i] 表示从序列的开始到第 i 个元素的和。
  2. 哈希表

    • 哈希表 mod_count 记录了每个余数出现的次数。
    • mod_count[mod] 表示前缀和的余数 mod 出现的次数。

算法步骤

  1. 计算前缀和

    • 遍历序列,计算每个位置的前缀和,并存储在 prefix_sum 数组中。
  2. 初始化哈希表

    • 初始化 mod_count[0] = 1,因为前缀和为 0 的情况(即从序列开始到当前位置的子序列和恰好是 b 的倍数)需要被考虑。
  3. 遍历前缀和数组

    • 对于每个前缀和 prefix_sum[i],计算其对 b 取余的结果 mod
    • 如果 mod_count 中已经存在 mod,说明之前有相同余数的前缀和,这些前缀和之间的子序列和是 b 的倍数。
    • 将 mod_count[mod] 的值加到 count 中,表示这些子序列的和是 b 的倍数。
    • 更新 mod_count[mod],记录当前余数 mod 的出现次数。
  4. 返回结果

    • 最终返回 count,即满足条件的连续子序列的数量。

详细步骤

  1. 初始化前缀和数组

    • prefix_sum = [0, 5, 15, 30, 50]
  2. 初始化哈希表

    • mod_count[0] = 1
  3. 遍历前缀和数组

    • i = 1prefix_sum[1] = 5mod = 5 % 5 = 0mod_count[0] = 1count = 1mod_count[0] = 2
    • i = 2prefix_sum[2] = 15mod = 15 % 5 = 0mod_count[0] = 2count = 3mod_count[0] = 3
    • i = 3prefix_sum[3] = 30mod = 30 % 5 = 0mod_count[0] = 3count = 6mod_count[0] = 4
    • i = 4prefix_sum[4] = 50mod = 50 % 5 = 0mod_count[0] = 4count = 10mod_count[0] = 5

详细解释

1. 初始化前缀和数组

前缀和数组 prefix_sum 记录了从序列开始到每个位置的和:

  • prefix_sum = [0, 5, 15, 30, 50]

2. 初始化哈希表

哈希表 mod_count 记录了每个余数出现的次数:

  • mod_count[0] = 1(初始化)

3. 遍历前缀和数组

我们逐个遍历前缀和数组,计算每个前缀和的余数,并更新哈希表和计数器。

3.1. i = 1
  • prefix_sum[1] = 5
  • mod = 5 % 5 = 0
  • mod_count[0] = 1(之前已经初始化为1)
  • count = 1(因为 mod_count[0] = 1,表示有一个前缀和的余数为0)
  • mod_count[0] = 2(更新哈希表,记录当前余数0的出现次数)
3.2. i = 2
  • prefix_sum[2] = 15
  • mod = 15 % 5 = 0
  • mod_count[0] = 2(之前已经更新为2)
  • count = 3(因为 mod_count[0] = 2,表示有两个前缀和的余数为0)
  • mod_count[0] = 3(更新哈希表,记录当前余数0的出现次数)
3.3. i = 3
  • prefix_sum[3] = 30
  • mod = 30 % 5 = 0
  • mod_count[0] = 3(之前已经更新为3)
  • count = 6(因为 mod_count[0] = 3,表示有三个前缀和的余数为0)
  • mod_count[0] = 4(更新哈希表,记录当前余数0的出现次数)
3.4. i = 4
  • prefix_sum[4] = 50
  • mod = 50 % 5 = 0
  • mod_count[0] = 4(之前已经更新为4)
  • count = 10(因为 mod_count[0] = 4,表示有四个前缀和的余数为0)
  • mod_count[0] = 5(更新哈希表,记录当前余数0的出现次数)

总结

通过使用前缀和数组和哈希表,我们可以在 O(n) 的时间复杂度内解决这个问题。前缀和数组帮助我们快速计算任意子序列的和,而哈希表则帮助我们记录每个余数出现的次数,从而快速找到满足条件的子序列。

使用了豆包ai帮助理解。