题目
小F面临一个有趣的挑战:给定一个数组,她需要将数组中的数字分为两组。分组的目标是使得一组数字的和的个位数等于给定的 A,另一组数字的和的个位数等于给定的 B。除此之外,还有一种特殊情况允许其中一组为空,但剩余数字和的个位数必须等于 A 或 B。小F需要计算所有可能的划分方式。
例如,对于数组 [1, 1, 1] 和目标 A = 1,B = 2,可行的划分包括三种:每个 1 单独作为一组,其余两个 1 形成另一组。如果 A = 3,B = 5,当所有数字加和的个位数为 3 或 5 时,可以有一组为非空,另一组为空。
理解题目是解决问题的第一步。让我们深入分析题目要求,确保我们对问题的理解是准确的。
题目理解
问题描述: 小F面临一个挑战:给定一个数组,她需要将数组中的数字分为两组。分组的目标是使得一组数字的和的个位数等于给定的 A,另一组数字的和的个位数等于给定的 B。除此之外,还有一种特殊情况允许其中一组为空,但剩余数字和的个位数必须等于 A 或 B。小F需要计算所有可能的划分方式。
关键点:
-
分组目标:
- 一组数字的和的个位数等于
A。 - 另一组数字的和的个位数等于
B。
- 一组数字的和的个位数等于
-
特殊情况:
- 允许其中一组为空,但剩余数字和的个位数必须等于
A或B。
- 允许其中一组为空,但剩余数字和的个位数必须等于
-
计算所有可能的划分方式:
- 需要计算所有满足上述条件的划分方式的数量。
示例:
-
示例1:
- 输入:
n = 3, A = 1, B = 2, array_a = [1, 1, 1] - 输出:
3 - 解释:可行的划分包括三种:每个 1 单独作为一组,其余两个 1 形成另一组。
- 输入:
-
示例2:
- 输入:
n = 3, A = 3, B = 5, array_a = [1, 1, 1] - 输出:
1 - 解释:所有数字加和的个位数为 3,可以有一组为非空,另一组为空。
- 输入:
解题思路
-
动态规划(DP) :
- 使用动态规划来记录每一步的状态。
dp[i][j][k]表示前i个数字,第一组的和的个位数为j,第二组的和的个位数为k时的划分方案数。
-
状态转移:
- 对于每个数字,可以选择将其加入第一组或第二组。
- 更新
dp[i][j][k]时,考虑当前数字加入第一组或第二组的情况。
-
特殊情况处理:
- 如果所有数字的总和的个位数等于
A或B,则可以有一组为空。
- 如果所有数字的总和的个位数等于
代码
public class Main {
public static int solution(int n, int A, int B, int[] array_a) {
// dp: dp[i][j][k] 表示前i个数字,个位数分别为j和k时的划分方案数
int[][][] dp = new int[n+1][10][10];
//初始化dp数组
dp[0][0][0] = 1;
int sum = 0;
// 第i个数
for(int i = 1;i <= array_a.length;i++){
//第一组
for(int j = 0;j < 10; j++){
//第二组
for(int k = 0;k < 10; k++){
//加入第一组
dp[i][j][k] += dp[i-1][((j + 10) - array_a[i-1] % 10) % 10][k];
//加入第二组
dp[i][j][k] += dp[i-1][j][((k + 10) - array_a[i-1] % 10) % 10];
}
}
//累加
sum += array_a[i-1];
}
//总和个位数是否为A
int a = sum % 10 == A ? 1:0;
//总和个位数是否为B
int b = sum % 10 == B ? 1:0;
int result = dp[n][A][B] + a + b;
return result;
}
public static void main(String[] args) {
int[] array1 = {1, 1, 1};
int[] array2 = {1, 1, 1};
int[] array3 = {1, 1};
System.out.println(solution(3, 1, 2, array1) == 3);
System.out.println(solution(3, 3, 5, array2) == 1);
System.out.println(solution(2, 1, 1, array3) == 2);
}
}
代码解释
-
动态规划数组
dp:dp[i][j][k]表示前i个数字,第一组的和的个位数为j,第二组的和的个位数为k时的划分方案数。dp[0][0][0] = 1表示前0个数字时,个位数分别为0和0的划分方案数为1。
-
遍历数组:
-
对于每个数字
array_a[i-1],遍历所有可能的个位数组合(j, k)。 -
更新
dp[i][j][k]:- 将当前数字加入第一组:
dp[i][j][k] += dp[i-1][((j + 10) - array_a[i-1] % 10) % 10][k] - 将当前数字加入第二组:
dp[i][j][k] += dp[i-1][j][((k + 10) - array_a[i-1] % 10) % 10]
- 将当前数字加入第一组:
-
-
累加总和:
- 计算所有数字的总和
sum。
- 计算所有数字的总和
-
判断总和的个位数:
- 如果总和的个位数等于
A,则a = 1,否则a = 0。 - 如果总和的个位数等于
B,则b = 1,否则b = 0。
- 如果总和的个位数等于
-
计算结果:
- 结果为
dp[n][A][B] + a + b,即所有数字的总和个位数为A或B的情况。
- 结果为
-
测试样例:
- 在
main方法中,通过测试样例验证代码的正确性。
- 在