本问题的目标是将一个整数数组划分为两组,使得每组数字的和的个位数分别等于给定的两个数 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;
}