卡牌翻面求和问题

40 阅读2分钟

def solution(n: int, a: list, b: list) -> int: MOD = 10**9 + 7 # 初始化动态规划数组 dp = [0, 0, 0] dp[0] = 1 # 初始时,和为0的方案数为1 for i in range(n): # 计算当前卡牌选择后的新方案数 new_dp = [0, 0, 0]
for r in range(3): # 对于每个余数r,可以选择a[i]或b[i] new_dp[(r + a[i]) % 3] = (new_dp[(r + a[i]) % 3] + dp[r]) % MOD new_dp[(r + b[i]) % 3] = (new_dp[(r + b[i]) % 3] + dp[r]) % MOD 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) 算法思路 这个问题可以看作是一个动态规划问题,我们需要计算在给定条件下,所有卡牌的选择使得最终和模3等于0的方案数。我们可以定义一个动态规划数组 dp,其中 dp[r] 表示当前和为模3余 r 的方案数。 初始化: dp[0] = 1:因为初始时,和为0(模3余0)的方案数为1(即不选择任何卡牌)。 dp[1] = 0 和 dp[2] = 0:因为初始时,和为模3余1或2的方案数为0。 迭代: 对于每一个卡牌 i,我们有两个选择:选择 a[i] 或 b[i]。 我们需要更新 dp 数组,考虑到所有可能的余数。 使用一个新的数组 new_dp 来暂存更新后的方案数,以避免直接修改 dp 数组导致的错误计算。 状态转移: 对于当前余数 r,如果选择 a[i],则新的余数为 (r + a[i]) % 3。 同样,如果选择 b[i],则新的余数为 (r + b[i]) % 3。 更新 new_dp 数组时,对于每种选择,我们将 dp[r] 的值加到 new_dp[(r + a[i]) % 3] 和 new_dp[(r + b[i]) % 3] 上,并对 MOD 取模,以避免整数溢出。 更新 dp 数组: 每次迭代完成后,将 new_dp 的值赋给 dp,为下一次迭代做准备。 结果: 最终的 dp[0] 即为所有卡牌选择后,和为模3余0的方案数。