小M有 n 张卡牌,每张卡牌的正反面分别写着不同的数字,正面是 𝑎𝑖,背面是 b i。小M希望通过选择每张卡牌的一面,使得所有向上的数字之和可以被3整除。你需要告诉小M,一共有多少种不同的方案可以满足这个条件。由于可能的方案数量过大,结果需要对 109+7取模。
例如:如果有3张卡牌,正反面数字分别为 (1,2),(2,3) 和 (3,2),你需要找到所有满足这3张卡牌正面或背面朝上的数字之和可以被3整除的组合数。
问题理解 题目要求我们通过选择每张卡牌的一面(正面或背面),使得所有向上的数字之和可以被3整除。我们需要计算出所有满足这个条件的组合数,并对结果取模 10^9+7。 数据结构选择 由于我们需要计算所有可能的组合数,并且结果需要对 10^9+7 取模,动态规划(Dynamic Programming, DP)是一个合适的方法。我们可以使用一个二维数组 dp 来存储中间结果。 算法步骤 定义状态: dp[i][j] 表示前 i 张卡牌中,选择某些面使得总和模3余 j 的方案数。 初始化: dp[0][0] = 1,表示不选择任何卡牌时,总和为0的方案数为1。 dp[0][1] = 0 和 dp[0][2] = 0,表示不选择任何卡牌时,总和模3余1或2的方案数为0。
python: def solution(n: int, a: list, b: list) -> int: MOD = 10**9 + 7 # dp[i][j] 表示前 i 张卡牌中,选择某些面使得总和模3余 j 的方案数 dp = [[0] * 3 for _ in range(n + 1)] dp[0][0] = 1 # 初始状态
for i in range(1, n + 1):
for j in range(3):
# 选择第 i 张卡牌的正面
dp[i][(j + a[i-1]) % 3] = (dp[i][(j + a[i-1]) % 3] + dp[i-1][j]) % MOD
# 选择第 i 张卡牌的背面
dp[i][(j + b[i-1]) % 3] = (dp[i][(j + b[i-1]) % 3] + dp[i-1][j]) % MOD
return dp[n][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 数组,考虑选择正面或背面的情况。 具体来说,对于第 i 张卡牌,如果选择正面,则更新 dp[i][(j + a[i-1]) % 3];如果选择背面,则更新 dp[i][(j + b[i-1]) % 3]。 最终结果: 最终结果存储在 dp[n][0] 中,表示前 n 张卡牌中,选择某些面使得总和模3余0的方案数。 复杂度分析 时间复杂度:O(n),其中 n 是卡牌的数量。我们需要遍历每一张卡牌,并对每个状态进行更新。 空间复杂度:O(n),我们使用了一个二维数组 dp 来存储中间结果。 总结 通过动态规划的方法,我们可以有效地计算出所有满足条件的组合数,并且能够在合理的时间内完成计算。