卡牌翻面求和问题 | 豆包MarsCode AI 刷题

92 阅读2分钟

题目

问题描述

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

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


测试样例

样例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张牌的时候,这i张牌向上的数字之和除以3的余数为j时,共有多少种方法。

初始化

  • dp[0][0] = 1,表示没有卡牌时,和为0的方案数为1。
  • dp[0][1] = 0dp[0][2] = 0,表示没有卡牌时,和为1或2的方案数为0。

状态转移

在这种设置下,我们就可以通过前i-1张牌的向上数字之和,以及第i个卡牌的向上数字获得dp[i]。并且根据题目条件提示,我们知道可能的方案数量过大,结果需要对 10^9+7取模,所以为了防止超出存储空间,我们可以对在计算每个元素的时候对dp进行取模操作。表达如下:

MOD = 10**9 + 7
dp[i][j] = (dp[i-1][(j - a[i-1]) % 3] + dp[i-1][(j - b[i-1]) % 3]) % MOD

结果

根据我们的定义设置dp[n][0]就是我们想要的结果,直接输出即可。

====

尾言 通过完成这道题目,我对于使用动态规划来解决问题有了更清晰的认识,希望以后再遇到类似题目的时候能够更快更准确地得到正确答案。