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

63 阅读3分钟

问题描述

小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

即满足条件的组合数有(1,3,2)(1,2,3)(2,2,2)三种。

问题理解

由题意可知,需要找到所有可能的卡牌组合,使得这些卡牌正面或背面朝上的数字之和可以被3整除。结果需要对 (10^9 + 7) 取模。可以使用动态规划(DP)来解决这个问题。将问题分为子问题,计算出每个子问题的解后记录下来,最后将其组合以得出最终的解。

具体来说,我们可以使用一个二维数组 dp,其中 dp[i][j] 表示前 i 张卡牌中,选择某些卡牌使得它们的和模3余数为 j 的方案数。

代码实践

以下是运用上述思路解决卡牌反面求和问题的Java代码

public class Main {
    public static int solution(int n, int[] a, int[] b) {
        // write code here
        final int MOD = 1000000007;
        // 初始化dp数组,dp[i][j]表示前i张卡牌中,和模3余数为j的方案数
        int[][] dp = new int[n + 1][3];
        dp[0][0] = 1; // 初始状态


        // 遍历每一张卡牌
        for (int i = 0; i < n; i++) {
            // 遍历当前所有可能的余数
            for (int j = 0; j < 3; j++) {
                if (dp[i][j] > 0) {
                    // 选择正面a[i]
                    dp[i + 1][(j + a[i]) % 3] = (dp[i + 1][(j + a[i]) % 3] + dp[i][j]) % MOD;
                    // 选择背面b[i]
                    dp[i + 1][(j + b[i]) % 3] = (dp[i + 1][(j + b[i]) % 3] + dp[i][j]) % MOD;
                }
            }
        }

        // 最终结果为dp[n][0]
        return dp[n][0];
    }

    public static void main(String[] args) {
        System.out.println(solution(3, new int[]{1, 2, 3}, new int[]{2, 3, 2}) == 3);
        System.out.println(solution(4, new int[]{3, 1, 2, 4}, new int[]{1, 2, 3, 1}) == 6);
        System.out.println(solution(5, new int[]{1, 2, 3, 4, 5}, new int[]{1, 2, 3, 4, 5}) == 32);
    }
}

代码分析

  1. 初始状态

    • 当没有选择任何卡牌时,和为0,模3余数为0,所以 dp[0][0] = 1
  2. 状态转移

    • 对于每一张卡牌 i,我们需要考虑两种选择:选择正面 a[i] 或选择背面 b[i]
    • 对于每一种选择,我们需要更新 dp[i+1][(j + a[i]) % 3] 和 dp[i+1][(j + b[i]) % 3]
    • 具体来说,如果当前状态 dp[i][j] 表示前 i 张卡牌中,和模3余数为 j 的方案数,那么选择正面 a[i] 后,新的和模3余数为 (j + a[i]) % 3,因此 dp[i+1][(j + a[i]) % 3] 需要加上 dp[i][j]
    • 同理,选择背面 b[i] 后,新的和模3余数为 (j + b[i]) % 3,因此 dp[i+1][(j + b[i]) % 3] 需要加上 dp[i][j]
  3. 结果

    • 最终结果为 dp[n][0],即前 n 张卡牌中,和模3余数为0的方案数。

总结

通过对本题的思考与学习,自己对动态规划方法的运用更加了解,对如何正确地进行状态转移有了进一步的学习。动态规划法有助于我们有效地计算出所有可能的组合,并找到满足条件的方案数,减少了计算次数,大大提高了运算效率。