问题描述
给定一个数组,请你把数组里的数字分为两组,使一组数字和的个位数等于 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 取余。
输入样例
样例 1
3 1 2
1 1 1
样例 2
3 3 5
1 1 1
样例 3
2 1 1
1 1
输出样例
样例 1
3
样例 2
1
样例 3
2
解题:
function solution(n, A, B, numbers) {
const MOD = 10000007; // 结果取模的常量
let totalSum = numbers.reduce((sum, num) => sum + num, 0); // 计算数组的总和
// 创建 dp 数组,记录形成各个位数和的组合数
let dp = new Array(10).fill(0); // dp[0] 到 dp[9],共 10 个元素
dp[0] = 1; // 形成和为 0 的方式有 1 种:不取任何数字
// 遍历数组中的每个数字
for (let num of numbers) {
// 从后向前更新 dp 数组,防止覆盖
for (let j = 9; j >= num; j--) {
dp[j] = (dp[j] + dp[j - num]) % MOD; // 更新组合数
}
}
// 计算符合条件的组合数
let count = 0;
// 处理一组为空的情况
count = (count + dp[A]) % MOD; // 和为 A 的组合数
count = (count + dp[B]) % MOD; // 和为 B 的组合数
// 处理两组都有数字的情况
for (let i = 0; i < 10; i++) {
if (i === A || i === B) continue; // 跳过 A 和 B
let j = (totalSum - i) % 10; // 剩余和的个位数
if ((i === A && j === B) || (i === B && j === A)) {
count = (count + dp[i]) % MOD; // 统计符合条件的组合数
}
}
return count; // 返回结果
}
function main() {
// You can add more test cases here
console.log(solution(3, 1, 2, [1, 1, 1]) === 3);
console.log(solution(3, 3, 5, [1, 1, 1]) === 1);
console.log(solution(2, 1, 1, [1, 1]) === 2);
}
main();