卡牌翻面求和问题,问题描述 小M有n张卡牌,每张卡牌的正反面分别写着不同的数字,正面是a,背面是b,小M希望通过选择每张卡牌的一面,使得所有向上的数字之和可以被3整除。你需要告诉小M,一共有多少种不同的方案可以满足这个条件。由于可能的方案数量过大,结果需要对10的9次方+7取模。
例如,如果有3张卡牌,正反面数字分别为(1,2),(2,3)和(3,2),你需要找到所有满足这3张卡牌正面或背面朝上的数字之和可以被3整除的组合数。
测试样例 样例一: 输入:n=3,a=[1,2,3],b=[2,3,2] 输出:3 样例二: 输入:n=4,a=[3,1,2,4],b=[1,2,3,1] 输出:6 样例三: 输入:n =5,a=[1,2,3,4,5],b=[1,2,3,4,5] 输出:32
解题思路
- 理解问题:我们需要选择每张卡牌的一面,使得所有向上的数字之和可以被3整除。
- 状态定义:我们可以定义
dp[i][j]表示前i张卡牌,使得数字之和模3余j的方案数。 - 状态转移:
- 对于每张卡牌,我们可以选择正面或背面。
- 更新
dp[i][j]时,考虑选择正面或背面的影响。
- 初始状态:
dp[0][0] = 1,表示没有卡牌时,和为0的方案数为1。 - 最终结果:
dp[n][0]即为所求的方案数。
代码提示
以下是代码的框架,其中关键步骤用注释标出:
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
# 遍历每一张卡牌
for i in range(1, n + 1):
# 当前卡牌的正面和背面数字
front = a[i - 1]
back = b[i - 1]
# 遍历所有可能的余数
for j in range(3):
# 选择正面的情况
dp[i][(j + front) % 3] = (dp[i][(j + front) % 3] + dp[i - 1][j]) % MOD
# 选择背面的情况
dp[i][(j + back) % 3] = (dp[i][(j + back) % 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数组:dp[i][j]表示前i张卡牌,使得数字之和模3余j的方案数。 - 状态转移:对于每张卡牌,更新
dp数组时,考虑选择正面或背面的影响。 - 最终结果:
dp[n][0]即为所求的方案数。
你可以根据这个框架继续完善代码,确保每一步都正确实现。