题目解析(四)| 豆包MarsCode AI刷题

118 阅读4分钟

题目解析

题目描述
小M有 n 张卡牌,每张卡牌的正反面分别写着不同的数字,正面是 a[i],背面是 b[i]。小M希望通过选择每张卡牌的一面,使得所有向上的数字之和可以被 3 整除。你需要告诉小M,一共有多少种不同的方案可以满足这个条件。由于可能的方案数量过大,结果需要对 109+710^9 + 7 取模。

image.png

输入输出格式

  • 输入

    • 一个整数 n 表示卡牌的数量。
    • 两个长度为 n 的数组 ab,分别表示每张卡牌的正面和背面的数字。
  • 输出

    • 返回一个整数,表示满足条件的方案数,结果对 109+710^9 + 7 取模。

示例

示例1
输入:
n = 3
a = [1, 2, 3]
b = [2, 3, 2]

输出:
3

示例2
输入:
n = 4
a = [3, 1, 2, 4]
b = [1, 2, 3, 1]

输出:
6

示例3
输入:
n = 5
a = [1, 2, 3, 4, 5]
b = [1, 2, 3, 4, 5]

输出:
32

思路分析

这个问题可以通过动态规划来解决。我们定义一个 DP 数组 dp[i][j],表示前 i 张卡牌选择某一面后,所有卡牌的数字之和模 3 等于 j 的方案数。

状态转移

  1. 初始状态

    • dp[0][0] = 1,表示没有卡牌时,数字和为 0 的方案数为 1(即不选任何卡牌)。
  2. 状态转移

    • 对于每一张卡牌 i,我们可以选择正面 a[i-1] 或背面 b[i-1],这两种选择分别会改变当前和的模 3 值。

    • 对于 dp[i][j],我们需要考虑:

      • 选择正面 a[i-1](j + a[i-1]) % 3
      • 选择背面 b[i-1](j + b[i-1]) % 3
    • 对于每一个选择,将相应的方案数累加到新的状态中。

  3. 目标

    • 最终的目标是 dp[n][0],即选择完所有卡牌后,数字和能被 3 整除的方案数。

动态规划表

  • dp[i][j]:表示前 i 张卡牌,数字和模 3 为 j 的方案数。
  • 状态转移时,每次选择当前卡牌的正面或背面,根据当前和模 3 的值更新 dp 数组。

代码实现

def solution(n: int, a: list, b: list) -> int:
    MOD = 10**9 + 7
    
    # 初始化DP数组,dp[i][j]表示前i张卡牌,和模3为j的方案数
    dp = [[0] * 3 for _ in range(n + 1)]
    dp[0][0] = 1  # 初始状态:0张卡牌,和为0的方案数为1
    
    # 状态转移
    for i in range(1, n + 1):
        for j in range(3):
            # 选择正面
            dp[i][(j + a[i - 1]) % 3] = (dp[i][(j + a[i - 1]) % 3] + dp[i - 1][j]) % MOD
            # 选择背面
            dp[i][(j + b[i - 1]) % 3] = (dp[i][(j + b[i - 1]) % 3] + dp[i - 1][j]) % MOD
    
    # 返回结果,即所有卡牌选择后,数字和能被3整除的方案数
    return dp[n][0]

代码说明

  1. MOD 常数:由于答案可能很大,所以我们使用 109+710^9 + 7 进行取模,避免溢出。

  2. DP 数组初始化

    • dp[i][j] 表示前 i 张卡牌,数字和模 3 等于 j 的方案数。
    • 初始状态为 dp[0][0] = 1,即没有卡牌时,数字和为 0 的方案数为 1。
  3. 状态转移

    • 对于每张卡牌 i,可以选择正面 a[i-1] 或背面 b[i-1],然后更新 DP 数组。
  4. 最终结果

    • 最终返回 dp[n][0],即所有卡牌选择完后,数字和能被 3 整除的方案数。

时间复杂度

  • 时间复杂度O(n * 3),其中 n 是卡牌的数量。对于每一张卡牌,我们需要更新三种可能的和模 3 的情况。因此,总时间复杂度是 O(n)
  • 空间复杂度O(n * 3),用于存储 DP 数组。

边界情况

  1. 最小输入:如果 n = 1,则只有两种选择(正面或背面),需要检查这两种情况是否满足条件。
  2. 所有卡牌的正反面数字相同:即所有 a[i] == b[i],此时问题变得简单,只需要选择一种情况。
  3. 大数情况:即 n 很大,确保在计算中对答案进行取模,以避免溢出。

示例分析

示例1
输入:
n = 3, a = [1, 2, 3], b = [2, 3, 2]

输出:
3
解释:通过选择卡牌的正面或背面,可以得到 3 种符合条件的方案。

示例2
输入:
n = 4, a = [3, 1, 2, 4], b = [1, 2, 3, 1]

输出:
6
解释:有 6 种选择,使得数字和模 3 为 0。