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

29 阅读3分钟

问题解析****

 

· 我们有 n 张卡牌,每张卡牌有正面数字(存储在列表 a 中)和背面数字(存储在列表 b 中)。

· 目标是找出通过选择每张卡牌的一面(正面或背面),使得所有向上的数字之和能被 3 整除的不同方案数量。

· 由于可能的方案数量非常大,所以最终结果要对 10^9 + 7 取模,以避免整数溢出等问题并得到一个合适范围内的结果。

解决步骤****

 

1. 状态定义

· 我们可以使用动态规划来解决这个问题。定义一个三维数组 dp,其中 dp[i][j][k] 表示考虑前 i 张卡牌,当前数字之和对 3 取模的结果为 j,且第 i 张卡牌选择的是第 k 面(k = 0 表示正面,k = 1 表示背面)的方案数量。

2. 初始化

· 当没有卡牌时(i = 0),只有一种情况,即数字之和为 0,且没有选择卡牌,所以 dp[0][0][0] = dp[0][0][1] = 1。这是因为不管是从正面还是背面开始考虑(虽然实际上还没选卡牌),和为 0 的情况有一种方案(就是什么都没选的初始状态)。

3. 状态转移

· 对于每张卡牌 i(从 1 到 n),我们要根据前 i - 1 张卡牌的状态来更新当前状态。

· 当考虑选择第 i 张卡牌的正面(k = 0)时:

· 对于和对 3 取模的每一种可能结果 j(j = 0, 1, 2),我们可以从 dp[i - 1][(j - a[i - 1] % 3 + 3) % 3][0] 和 dp[i - 1][(j - a[i - 1] % 3 + 3) % 3][1] 转移过来。这里 (j - a[i - 1] % 3 + 3) % 3 是为了处理负数取模的情况,确保得到正确的前序状态索引。

· 即 dp[i][j][0] = (dp[i - 1][(j - a[i - 1] % 3 + 3) % 3][0] + dp[i - 1][(j - a[i - 1] % 3 + 3) % 3][1]) % MOD,其中 MOD = 10**9 + 7。

· 当考虑选择第 i 张卡牌的背面(k = 1)时:

· 同样对于和对 3 取模的每一种可能结果 j(j = 0, 1, 2),我们从 dp[i - 1][(j - b[i - 1] % 3 + 3) % 3][0] 和 dp[i - 1][(j - b[i - 1] % 3 + 3) % 3][1] 转移过来。

· 即 dp[i][j][1] = (dp[i - 1][(j - b[i - 1] % 3 + 3) % 3][0] + dp[i - 1][(j - b[i - 1] % 3 + 3) % 3][1]) % MOD。

4. 最终结果

· 考虑完所有 n 张卡牌后,满足条件的方案总数就是 dp[n][0][0] + dp[n][0][1],因为我们要的是所有数字之和能被 3 整除的情况(对 3 取模结果为 0),并且最后一张卡牌可以选择正面或背面。

代码实现****

 

MOD = 10**9 + 7  

 

def solution(n: int, a: list, b: list) -> int:  

    dp = [[0, 0, 0] for _ in range(n + 1)]  

    dp[0][0] = 1    

 

    for i in range(1, n + 1):  

 

        prev_dp = dp[i - 1][:]  

           

        for j in range(3):  

             

            new_remainder = (j + a[i - 1]) % 3  

            dp[i][new_remainder] = (dp[i][new_remainder] + prev_dp[j]) % MOD  

               

            new_remainder = (j + b[i - 1]) % 3  

            dp[i][new_remainder] = (dp[i][new_remainder] + prev_dp[j]) % MOD  

 

    return dp[n][0]

 

if name == 'main':

    print(solution(n = 3, a = [1, 2, 3], b = [2, 3, 2]))

    print(solution(n = 4, a = [3, 1, 2, 4], b = [1, 2, 3, 1]))

    print(solution(n = 5, a = [1, 2, 3, 4, 5], b = [1, 2, 3, 4, 5]))

 

在上述代码中:

 

· 首先定义了常量 MOD 为 10**9 + 7,用于取模操作。

· 然后创建了三维数组 dp 并进行初始化。

· 通过两层循环,分别遍历每张卡牌和数字和对 3 取模的各种情况,根据状态转移方程更新 dp 数组。

· 最后返回满足所有数字之和能被 3 整除的方案总数,即 dp[n][0][0] + dp[n][0][1] 对 MOD 取模的结果。