豆包33 卡牌翻面求和问题

159 阅读2分钟

问题描述

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

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

算法选择

dfs + 记忆化搜索

算法思路

  1. 初始化

    • 创建一个二维数组memo,用于存储动态规划的结果,其中memo[i][j]表示在前i张卡牌中选择数字,使得这些数字之和模3等于j的方案数。
    • memo数组中的所有元素初始化为-1,表示尚未计算。
  2. 深度优先搜索(DFS)

    • 定义一个递归函数dfs(i, j),表示在前i张卡牌中选择数字,使得这些数字之和模3等于j的方案数。
    • 如果i < 0,即没有卡牌可选,那么只有当j == 0时,方案数为1(表示和为0),否则方案数为0。
    • 如果memo[i][j]不等于-1,直接返回memo[i][j]的值,表示已经计算过。
    • 否则,计算dfs(i - 1, ((j + a[i]) % 3))dfs(i - 1, ((j + b[i]) % 3)),分别表示选择第i张卡牌的正面和背面的方案数。
    • 将这两个方案数相加,并对结果取模(MOD = 1e9 + 7),然后存储在memo[i][j]中。
  3. 返回结果

    • 最终,dfs(n - 1, 0)的值就是所有方案中,数字之和可以被3整除的方案数。

代码展示

public class Main {
    private static int[][] memo;
    private static final int MOD = (int) (1e9 + 7);

    public static int solution(int n, int[] a, int[] b) {
        memo = new int[n][3];
        for (int i = 0; i < n; i++) {
            Arrays.fill(memo[i], -1);
        }
        return dfs(n - 1, 0, a, b);
    }

    // dfs(i, j): 表示从(0-i)范围内选取元素,
    // j: 已选数字之和 % 3 == j
    // dfs(-1, 0) = 1, dfs(-1, 1) = 0 dfs(-1, 2) = 0
    // dfs(i, j) = dfs(i-1, (j+a)%3) + dfs(i-1, j)
    public static int dfs(int i, int j, int[] a, int[] b) {
        if (i < 0) {
            if (j == 0) {
                return 1;
            } else {
                return 0;
            }
        }
        if (memo[i][j] != -1) {
            return memo[i][j];
        }
        long res = 0;
        res =  dfs(i - 1, ((j + a[i]) % 3), a, b) + dfs(i - 1, ((j + b[i]) % 3), a, b);
        return memo[i][j] = (int) (res % MOD);
    }

    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);
    }
}