题目
问题描述
小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] = 0,dp[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]就是我们想要的结果,直接输出即可。
====
尾言 通过完成这道题目,我对于使用动态规划来解决问题有了更清晰的认识,希望以后再遇到类似题目的时候能够更快更准确地得到正确答案。