青训营X豆包MarsCode 技术训练营第一课

38 阅读3分钟

小M有 𝑛n 张卡牌,每张卡牌的正反面分别写着不同的数字,正面是 𝑎𝑖ai​,背面是 𝑏𝑖bi​。小M希望通过选择每张卡牌的一面,使得所有向上的数字之和可以被3整除。你需要告诉小M,一共有多少种不同的方案可以满足这个条件。由于可能的方案数量过大,结果需要对 109+7109+7 取模。

例如:如果有3张卡牌,正反面数字分别为 (1,2)(2,3) 和 (3,2),你需要找到所有满足这3张卡牌正面或背面朝上的数字之和可以被3整除的组合数。

问题理解

你需要找到所有可能的卡牌组合,使得这些卡牌正面或背面朝上的数字之和可以被3整除。每张卡牌有两个选择:正面或背面。

数据结构选择

由于我们需要计算所有可能的组合,并且需要快速判断一个组合是否满足条件,动态规划(DP)是一个合适的选择。我们可以使用一个数组来记录当前所有可能的和模3的结果。

算法步骤

  1. 初始化:创建一个长度为3的数组 dp,用于记录当前所有可能的和模3的结果。初始时,dp[0] 为1(表示和为0的情况),其他为0。

  2. 状态转移

    • 对于每一张卡牌,我们有两个选择:正面或背面。
    • 对于每一个选择,更新 dp 数组。具体来说,对于当前的 dp[i],我们可以通过加上卡牌的正面或背面数字来更新 dp[(i + a_i) % 3] 和 dp[(i + b_i) % 3]
  3. 结果:最终,dp[0] 就是所有满足条件的组合数。

总结

通过动态规划,我们可以高效地计算出所有满足条件的组合数。关键在于如何更新 dp 数组,确保每一步都考虑到所有可能的选择。 好的,让我们详细讨论如何使用动态规划来解决这个问题。 动态规划思路 定义状态: 我们使用一个长度为3的数组 dp,其中 dp[i] 表示当前所有可能的和模3等于 i 的组合数。 初始化: 初始时,dp[0] = 1,表示和为0的情况有一种(即什么都不选),其他 dp[1] 和 dp[2] 初始为0。 状态转移: 对于每一张卡牌,我们有两个选择:正面或背面。 对于每一个选择,更新 dp 数组。具体来说,对于当前的 dp[i],我们可以通过加上卡牌的正面或背面数字来更新 dp[(i + a_i) % 3] 和 dp[(i + b_i) % 3]。 结果: 最终,dp[0] 就是所有满足条件的组合数。 代码框架 python def solution(n: int, a: list, b: list) -> int:    MOD = 10**9 + 7        # 初始化dp数组    dp = [0] * 3    dp[0] = 1        # 遍历每一张卡牌    for i in range(n):        # 创建一个新的dp数组来        存储更新后的结果        new_dp = [0] * 3                # 更新dp数组        for j in range(3):            if dp[j] > 0:                new_dp[(j +                 a[i]) % 3]                 = (new_dp                [(j + a[i])                 % 3] + dp                [j]) % MOD                new_dp[(j +                 b[i]) % 3]                 = (new_dp                [(j + b[i])                 % 3] + dp                [j]) % MOD                # 将new_dp赋值给dp        dp = new_dp        # 返回结果    return dp[0]if name == 'main':    print(solution(n = 3, a     = [1, 2, 3], b = [2, 3,     2]) == 3)    print(solution(n = 4, a     = [3, 1, 2, 4], b = [1,     2, 3, 1]) == 6)    print(solution(n = 5, a     = [1, 2, 3, 4, 5], b =     [1, 2, 3, 4, 5]) == 32)

关键步骤解释 初始化: dp = [0] * 3 初始化一个长度为3的数组,dp[0] = 1 表示和为0的情况有一种。 状态转移: 对于每一张卡牌,我们创建一个新的 new_dp 数组来存储更新后的结果。 对于每一个可能的和模3的结果 j,我们更新 new_dp[(j + a[i]) % 3] 和 new_dp[(j + b[i]) % 3]。 结果: 最终,dp[0] 就是所有满足条件的组合数。