问题描述
小M是一个五年级的小学生,今天他学习了整除的知识,想通过一些练习来巩固自己的理解。他写下了一个长度为 n 的正整数序列 a_0, a_1, ..., a_{n-1},然后想知道有多少个连续子序列的和能够被一个给定的正整数 b 整除。你能帮小M解决这个问题吗?
解题思路
-
理解问题:
- 我们需要找出给定序列中有多少个连续子序列的和能被一个给定的正整数
b整除。
- 我们需要找出给定序列中有多少个连续子序列的和能被一个给定的正整数
-
前缀和的概念:
- 前缀和是一个数组中从开始到当前位置的所有元素的和。例如,对于序列
[1, 2, 3],前缀和数组为[1, 3, 6]。 - 通过前缀和,我们可以快速计算任意子序列的和。
- 前缀和是一个数组中从开始到当前位置的所有元素的和。例如,对于序列
-
模运算的应用:
- 如果两个前缀和的模
b相同,那么这两个前缀和之间的子序列的和就能被b整除。 - 例如,如果
prefix_sum[i] % b == prefix_sum[j] % b,那么sequence[i+1]到sequence[j]的子序列和能被b整除。
- 如果两个前缀和的模
-
哈希表的使用:
- 我们可以使用一个哈希表(字典)来记录每个前缀和模
b出现的次数。 - 这样可以在遍历过程中快速计算出符合条件的子序列数量。
- 我们可以使用一个哈希表(字典)来记录每个前缀和模
算法步骤
-
初始化:
- 初始化一个变量
prefix_sum用于存储当前的前缀和。 - 初始化一个哈希表
mod_count,用于记录每个前缀和模b出现的次数。特别地,初始化mod_count[0] = 1,因为前缀和为 0 的情况已经存在一次。
- 初始化一个变量
-
遍历序列:
- 对于序列中的每个元素
num,更新prefix_sum。 - 计算当前前缀和模
b的值current_mod。 - 如果
current_mod已经在mod_count中,说明存在子序列和能被b整除,将result增加mod_count[current_mod]的值,并将mod_count[current_mod]加 1。 - 如果
current_mod不在mod_count中,将其初始化为 1。
- 对于序列中的每个元素
-
返回结果:
- 最后返回
result,即符合条件的子序列数量。
- 最后返回
总结
通过使用前缀和和模运算,我们可以高效地计算出符合条件的子序列数量。哈希表的使用使得我们可以在 O(n) 的时间复杂度内解决这个问题。 代码
def solution(n, b, sequence):
# 初始化前缀和数组和哈希表
prefix_sum = 0
mod_count = {0: 1} # 初始化模为0的情况
result = 0
for num in sequence:
# 计算当前前缀和
prefix_sum += num
# 计算当前前缀和模 b 的值
current_mod = prefix_sum % b
# 如果当前模已经在哈希表中,说明存在子序列和能被 b 整除
if current_mod in mod_count:
result += mod_count[current_mod]
mod_count[current_mod] += 1
else:
mod_count[current_mod] = 1
return result
if __name__ == "__main__":
# 你可以添加更多测试用例
sequence = [1, 2, 3]
print(solution(3, 3, sequence) == 3)