小F的分组挑战 | 豆包MarsCode AI刷题

44 阅读3分钟

题目描述

小F需要将一个数组分为两组,使得:

  1. 一组数字的和的个位数等于给定值 AA
  2. 另一组数字的和的个位数等于给定值 BB

允许一种特殊情况:

  • 其中一组为空,但剩余数字的和的个位数必须等于 AABB

小F需要计算所有满足要求的分组方式。

示例:

  • 输入:

    n = 3, A = 1, B = 2, array_a = [1, 1, 1]
    

    输出:3

  • 输入:

    n = 3, A = 3, B = 5, array_a = [1, 1, 1]
    

    输出:1

解题思路

本题需要用到动态规划位运算的结合来解决。

1. 问题建模

  • 我们可以枚举每个数字是否属于某一组,通过记录两组和的状态来判断是否满足条件。
  • 用动态规划来存储和状态,记录可能的划分方式。

关键点

  • 所有数字总和的个位数决定了是否可以分成两组满足条件;否则直接返回 0。
  • 动态规划的核心是逐步更新可能的和状态。

2. 动态规划状态设计

状态定义

  • 使用一个二维数组 dp[i][x] 表示前 ii 个数字中可以组成和的个位数为 xx 的分组方式数。

状态转移

  • 遍历数组中的每个数字,将其加入到可能的当前和中:
    • 假设当前数字为 vv,尝试加入到各个位数状态 xx 中:
      • 新的状态为 (x+v)(x + v) \\% 10

初始条件

  • dp[0][0]=1dp[0][0] = 1,表示还未加入任何数字时,和为 0 的状态。

3. 特殊情况处理

  • 如果所有数字总和的个位数不等于 AABB,则直接输出 0。
  • 允许某一组为空的条件下,总和的个位数等于 AABB 时,直接考虑特殊情况。

4. 优化

  • 使用滚动数组优化空间复杂度,将状态压缩为一维数组。

代码详解

以下是代码实现及注释:

# 定义求解函数
def count_partitions(n, A, B, array_a):
    # 计算总和的个位数
    total_sum = sum(array_a) % 10

    # 特殊情况:总和的个位数不能满足 A 或 B
    if total_sum != A and total_sum != B:
        return 0

    # 动态规划初始化
    dp = [0] * 10
    dp[0] = 1  # 初始状态

    # 遍历数组,更新状态
    for num in array_a:
        next_dp = dp[:]
        for x in range(10):
            next_dp[(x + num) % 10] += dp[x]
        dp = next_dp

    # 计算结果
    result = dp[A] + dp[B]
    return result

# 测试样例
print(count_partitions(3, 1, 2, [1, 1, 1]))  # 输出:3
print(count_partitions(3, 3, 5, [1, 1, 1]))  # 输出:1
print(count_partitions(2, 1, 1, [1, 1]))      # 输出:2
print(count_partitions(5, 3, 7, [2, 3, 5, 7, 9]))  # 输出:0

知识总结

动态规划总结

  • 状态设计:将问题分解为子问题,定义状态存储计算结果。
  • 状态转移方程:清晰描述如何从上一个状态推导到当前状态。
  • 边界条件:考虑初始状态和特殊情况。

数学知识

  • 模运算 \\% 的性质在问题中多次出现,理解其在动态规划中的作用。
  • 总和的个位数是关键分析点,通过数学计算可以简化问题。

学习计划

1. 制定刷题计划

  • 每天练习 3-5 道动态规划相关题目,逐步提升思维能力。
  • 将题目分为初级(如简单路径问题)、中级(如背包问题)、高级(如本题)。

2. 利用错题进行针对性学习

  • 每次错题后重新分析,归纳出错误的原因(如状态定义或转移错误)。
  • 使用豆包MarsCode AI的题目推荐功能,练习相似题目。

3. 提升方法

  • 学会画出状态转移图,将抽象问题具体化。
  • 对复杂问题分步骤拆解,降低理解难度。

学习建议

  • 对于入门同学:从简单题目入手,逐步理解动态规划思想。
  • 每天记录刷题心得,形成自己的知识库。通过多练习和反思,让思维更加敏捷,逐步攻克更复杂的题目。