问题描述
给定一个数组,请你把数组里的数字分为两组,使一组数字和的个位数等于 A(1 ≤ A ≤ 9),且剩余数字和的个位数等于 B(1 ≤ B ≤ 9);或者一组数字的个数为零,但剩余数字和的个位数等于 A 或 B。请问一共有多少种划分方式?
备注:
- 数组里的数字可以相等,但每个数字都是独一无二的。
比如数组 a 等于[1, 1, 1],A 等于 1,B 等于 2,则一共有三组划分方式:
第一种:
A:a[0]
B:a[1]、a[2]
第二种:
A:a[1]
B:a[0]、a[2]
第三种:
A:a[2]
B:a[0]、a[1] - 可以将所有数字都划分到同一组,使其和的个位数等于 A 或 B;另一组为空
比如数组 a 等于[1, 1, 1],A 等于 3,B 等于 5,则共有一组划分方式:
A:a[0]、a[1]、a[2]
B:空
输入格式
输入第一行包含三个整数 n、A、B(1 ≤ n ≤ 100000,1 ≤ A ≤ 9,1 ≤ B ≤ 9),n 代表需要数组中的数字个数。
第二行,有 n 个元素,代表数组内的数字(1 ≤ 每个数字 ≤ 9)。
输出格式
输出一共有多少种划分方式,结果对 10000007 取余。
样例一
输入:
3 1 2
1 1 1
输出:
3
样例 2
输入:
3 3 5
1 1 1
输出:
1
样例 3
输入:
2 1 1
1 1
输出:
2
问题理解
这道题让我们求组合数,即可以将数字分成两组,也可以把数字全部放到一组,剩下一组不放数字。第一种情况我们并不知道他是哪个数字放哪个组,要我们求组合数,我们可以用动态规划来解决;第二种情况,我们直接把所有数字累加之后取个位数,看它是否等于A或者等于B
数据结构选择
由于数组中的数字范围在1到9之间,我们可以考虑使用动态规划(DP)来解决这个问题。
算法步骤
- 初始化:创建一个三维数组
dp,初始化dp[0][0][0] = 1,表示没有任何数字时,和为0的情况。 - 遍历数组:正常遍历数组,三个for循环,第一个表示第i个数,第二个表示第一组的个位数,第三个表示第二组的个位数。
- 结果计算:遍历
dp[n][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);
}
}
豆包ai给了我解题思路,让我更好的运用DP算法,递推公式。