二分数组| 豆包MarsCode AI刷题

42 阅读3分钟

本问题的目标是将一个整数数组划分为两组,使得每组数字的和的个位数分别等于给定的两个数 AAA 和 BBB,并且允许其中一组为空。题目要求计算所有满足条件的划分方式。

1. 问题分析

给定一个数组 array_a,我们需要将其分为两组 GAG_AGA​ 和 GBG_BGB​,使得:

  • GAG_AGA​ 的和的个位数为 AAA;
  • GBG_BGB​ 的和的个位数为 BBB。

此外,我们允许有一种特殊情况:其中一组可以为空,剩余数字的和的个位数必须等于 AAA 或 BBB。

为了方便求解,我们需要通过动态规划来逐步计算每一种可能的划分方式。

2. 动态规划设计

我们可以通过动态规划来解决这个问题。我们定义一个三维 DP 数组 dp[i][rA][rB],其中:

  • iii 表示当前考虑到数组中的第 iii 个元素;
  • rArArA 表示到目前为止,分配给组 AAA 的数字和的个位数;
  • rBrBrB 表示到目前为止,分配给组 BBB 的数字和的个位数。

dp[i][rA][rB] 的含义是:前 iii 个数字中,组 AAA 的和的个位数为 rArArA,组 BBB 的和的个位数为 rBrBrB 的方案数。

3. 状态转移

  • 对于每个数字 numnumnum,我们可以选择将其放入组 AAA 或组 BBB:

    • 如果将 numnumnum 放入组 AAA,则新的 rArArA 为 (rA+num)%10(rA + num) % 10(rA+num)%10;
    • 如果将 numnumnum 放入组 BBB,则新的 rBrBrB 为 (rB+num)%10(rB + num) % 10(rB+num)%10。

    因此,状态转移公式为:

    • dp[i][(rA+num)%10][rB]+=dp[i−1][rA][rB]dp[i][(rA + num) % 10][rB] += dp[i-1][rA][rB]dp[i][(rA+num)%10][rB]+=dp[i−1][rA][rB];
    • dp[i][rA][(rB+num)%10]+=dp[i−1][rA][rB]dp[i][rA][(rB + num) % 10] += dp[i-1][rA][rB]dp[i][rA][(rB+num)%10]+=dp[i−1][rA][rB]。

4. 边界条件

  • 初始状态:dp[0][0][0] = 1,表示没有数字时,组 AAA 和组 BBB 的和的个位数都是 0,只有一种方式。

5. 特殊情况处理

除了正常的划分方式外,还需要考虑两种特殊情况:

  • 组 BBB 为空,组 AAA 的和的个位数为 AAA;
  • 组 AAA 为空,组 BBB 的和的个位数为 BBB。

因此,在动态规划计算完成后,我们需要额外加上这两种情况的计数:

  • dp[n][rA][0] 中,若 rA=ArA = ArA=A,则说明组 AAA 的和的个位数为 AAA,组 BBB 为空;
  • dp[n][0][rB] 中,若 rB=BrB = BrB=B,则说明组 BBB 的和的个位数为 BBB,组 AAA 为空。

6. 结果

最终,我们求解的结果是:dp[n][A][B](正常划分)加上特殊情况的计数。

7. 代码实现

public static int solution(int n, int A, int B, int[] array_a) {
    // 定义常量 MOD,避免数值溢出
    final int MOD = 1000000007;

    // 初始化动态规划数组 dp
    int[][][] dp = new int[n + 1][10][10];
    dp[0][0][0] = 1;  // 初始状态,前 0 个数字,A 和 B 都是 0

    // 遍历数组中的每个数字
    for (int i = 1; i <= n; i++) {
        int num = array_a[i - 1];  // 当前数字

        // 遍历 rA 和 rB(个位数范围是 0 到 9)
        for (int rA = 0; rA < 10; rA++) {
            for (int rB = 0; rB < 10; rB++) {
                // 当前数加入到 A 组
                int new_rA = (rA + num) % 10;
                dp[i][new_rA][rB] = (dp[i][new_rA][rB] + dp[i - 1][rA][rB]) % MOD;

                // 当前数加入到 B 组
                int new_rB = (rB + num) % 10;
                dp[i][rA][new_rB] = (dp[i][rA][new_rB] + dp[i - 1][rA][rB]) % MOD;
            }
        }
    }

    // 计算满足条件的方案数
    int result = dp[n][A][B];  // 正常分为 A 和 B 两组的情况

    // 还要加上全放入一组的情况(另一组为空的情况)
    for (int rA = 0; rA < 10; rA++) {
        if (rA == A) {
            result = (result + dp[n][rA][0]) % MOD;  // 组 B 为空,组 A 的和为 A
        }
        if (rA == B) {
            result = (result + dp[n][0][rA]) % MOD;  // 组 A 为空,组 B 的和为 B
        }
    }

    return result;
}