问题描述
小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 整除。
数据结构的选择
-
前缀和数组:
- 前缀和数组
prefix_sum记录了从序列开始到每个位置的和。 prefix_sum[i]表示从序列的开始到第i个元素的和。
- 前缀和数组
-
哈希表:
- 哈希表
mod_count记录了每个余数出现的次数。 mod_count[mod]表示前缀和的余数mod出现的次数。
- 哈希表
算法步骤
-
计算前缀和:
- 遍历序列,计算每个位置的前缀和,并存储在
prefix_sum数组中。
- 遍历序列,计算每个位置的前缀和,并存储在
-
初始化哈希表:
- 初始化
mod_count[0] = 1,因为前缀和为0的情况(即从序列开始到当前位置的子序列和恰好是b的倍数)需要被考虑。
- 初始化
-
遍历前缀和数组:
- 对于每个前缀和
prefix_sum[i],计算其对b取余的结果mod。 - 如果
mod_count中已经存在mod,说明之前有相同余数的前缀和,这些前缀和之间的子序列和是b的倍数。 - 将
mod_count[mod]的值加到count中,表示这些子序列的和是b的倍数。 - 更新
mod_count[mod],记录当前余数mod的出现次数。
- 对于每个前缀和
-
返回结果:
- 最终返回
count,即满足条件的连续子序列的数量。
- 最终返回
详细步骤
-
初始化前缀和数组:
prefix_sum = [0, 5, 15, 30, 50]
-
初始化哈希表:
mod_count[0] = 1
-
遍历前缀和数组:
i = 1,prefix_sum[1] = 5,mod = 5 % 5 = 0,mod_count[0] = 1,count = 1,mod_count[0] = 2i = 2,prefix_sum[2] = 15,mod = 15 % 5 = 0,mod_count[0] = 2,count = 3,mod_count[0] = 3i = 3,prefix_sum[3] = 30,mod = 30 % 5 = 0,mod_count[0] = 3,count = 6,mod_count[0] = 4i = 4,prefix_sum[4] = 50,mod = 50 % 5 = 0,mod_count[0] = 4,count = 10,mod_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] = 5mod = 5 % 5 = 0mod_count[0] = 1(之前已经初始化为1)count = 1(因为mod_count[0] = 1,表示有一个前缀和的余数为0)mod_count[0] = 2(更新哈希表,记录当前余数0的出现次数)
3.2. i = 2
prefix_sum[2] = 15mod = 15 % 5 = 0mod_count[0] = 2(之前已经更新为2)count = 3(因为mod_count[0] = 2,表示有两个前缀和的余数为0)mod_count[0] = 3(更新哈希表,记录当前余数0的出现次数)
3.3. i = 3
prefix_sum[3] = 30mod = 30 % 5 = 0mod_count[0] = 3(之前已经更新为3)count = 6(因为mod_count[0] = 3,表示有三个前缀和的余数为0)mod_count[0] = 4(更新哈希表,记录当前余数0的出现次数)
3.4. i = 4
prefix_sum[4] = 50mod = 50 % 5 = 0mod_count[0] = 4(之前已经更新为4)count = 10(因为mod_count[0] = 4,表示有四个前缀和的余数为0)mod_count[0] = 5(更新哈希表,记录当前余数0的出现次数)
总结
通过使用前缀和数组和哈希表,我们可以在 O(n) 的时间复杂度内解决这个问题。前缀和数组帮助我们快速计算任意子序列的和,而哈希表则帮助我们记录每个余数出现的次数,从而快速找到满足条件的子序列。
使用了豆包ai帮助理解。