题目
小F面临一个有趣的挑战:给定一个数组,她需要将数组中的数字分为两组。分组的目标是使得一组数字的和的个位数等于给定的 A,另一组数字的和的个位数等于给定的 B。除此之外,还有一种特殊情况允许其中一组为空,但剩余数字和的个位数必须等于 A 或 B。小F需要计算所有可能的划分方式。
描述
给定一个整数数组 array_a 和两个整数 A 和 B,计算所有可能的划分方式,使得一组数字的和的个位数等于 A,另一组数字的和的个位数等于 B。允许其中一组为空,但剩余数字和的个位数必须等于 A 或 B。
解题思路
-
预处理数组:
- 将数组中的每个元素取模 10,因为只关心个位数。
-
特殊情况处理:
- 计算数组的总和的个位数
total_sum。 - 如果
total_sum等于A或B,则直接返回 1,因为可以将所有数字放在一组,另一组为空。
- 计算数组的总和的个位数
-
动态规划:
-
使用二维数组
f,其中f[i][j]表示前i个元素中,一组和的个位数为j的划分方式数。 -
初始化
f[0][0] = 1,表示没有任何元素时,和为 0 的划分方式数为 1。 -
遍历数组,更新
f数组:- 对于每个元素
array_a[i-1],可以选择将其放入当前组或另一组。 - 更新
f[i][j]为f[i-1][j]加上f[i-1][(j - array_a[i-1] + 10) % 10]。
- 对于每个元素
-
-
返回结果:
- 返回
f[n][B],即前n个元素中,一组和的个位数为B的划分方式数。
- 返回
代码详解
预处理数组
def solution(n, A, B, array_a):
array_a = [x % 10 for x in array_a]
-
取模操作:
- 将数组中的每个元素取模 10,只保留个位数。
特殊情况处理
total_sum = sum(array_a)
total_sum %= 10
if (total_sum == A or total_sum == B):
return 1
if (total_sum != (A + B) % 10):
return 0
-
计算总和的个位数:
- 计算数组的总和
total_sum并取模 10。
- 计算数组的总和
-
特殊情况处理:
- 如果
total_sum等于A或B,直接返回 1。 - 如果
total_sum不等于(A + B) % 10,直接返回 0。
- 如果
动态规划
f = [[0 for _ in range(10)] for _ in range(n + 1)]
f[0][0] = 1
for i in range(1, n + 1):
for j in range(10):
f[i][j] += f[i - 1][j]
f[i][j] += f[i - 1][(j - array_a[i - 1] + 10) % 10]
-
初始化:
f[0][0] = 1,表示没有任何元素时,和为 0 的划分方式数为 1。
-
动态规划更新:
- 遍历数组,更新
f数组。 - 对于每个元素
array_a[i-1],可以选择将其放入当前组或另一组。 - 更新
f[i][j]为f[i-1][j]加上f[i-1][(j - array_a[i-1] + 10) % 10]。
- 遍历数组,更新
返回结果
return f[n][B]
返回 f[n][B],即前 n 个元素中,一组和的个位数为 B 的划分方式数。
测试用例解析
测试用例1
输入:n = 3, A = 1, B = 2, array_a = [1, 1, 1]
预处理数组
array_a = [x % 10 for x in array_a]
- 将数组中的每个元素取模 10,只保留个位数。
- 结果:
array_a = [1, 1, 1]
特殊情况处理
total_sum = sum(array_a)
total_sum %= 10
if (total_sum == A or total_sum == B):
return 1
if (total_sum != (A + B) % 10):
return 0
-
计算数组的总和
total_sum并取模 10。total_sum = 1 + 1 + 1 = 3total_sum % 10 = 3
-
检查特殊情况:
total_sum == 3,既不等于A = 1,也不等于B = 2。total_sum % 10 != (A + B) % 10,即3 != (1 + 2) % 10。
-
不满足特殊情况,继续进行动态规划。
动态规划
f = [[0 for _ in range(10)] for _ in range(n + 1)]
f[0][0] = 1
for i in range(1, n + 1):
for j in range(10):
f[i][j] += f[i - 1][j]
f[i][j] += f[i - 1][(j - array_a[i - 1] + 10) % 10]
初始化
f是一个二维数组,f[i][j]表示前i个元素中,一组和的个位数为j的划分方式数。- 初始化
f[0][0] = 1,表示没有任何元素时,和为 0 的划分方式数为 1。
动态规划过程
-
第1个元素:
-
i = 1,array_a[0] = 1 -
对于
j从 0 到 9:f[1][0] = f[0][0] + f[0][(0 - 1 + 10) % 10] = 1 + 0 = 1f[1][1] = f[0][1] + f[0][(1 - 1 + 10) % 10] = 0 + 1 = 1f[1][2] = f[0][2] + f[0][(2 - 1 + 10) % 10] = 0 + 0 = 0f[1][3] = f[0][3] + f[0][(3 - 1 + 10) % 10] = 0 + 0 = 0f[1][4] = f[0][4] + f[0][(4 - 1 + 10) % 10] = 0 + 0 = 0f[1][5] = f[0][5] + f[0][(5 - 1 + 10) % 10] = 0 + 0 = 0f[1][6] = f[0][6] + f[0][(6 - 1 + 10) % 10] = 0 + 0 = 0f[1][7] = f[0][7] + f[0][(7 - 1 + 10) % 10] = 0 + 0 = 0f[1][8] = f[0][8] + f[0][(8 - 1 + 10) % 10] = 0 + 0 = 0f[1][9] = f[0][9] + f[0][(9 - 1 + 10) % 10] = 0 + 0 = 0
-
结果:
f[1] = [1, 1, 0, 0, 0, 0, 0, 0, 0, 0]
-
-
第2个元素:
-
i = 2,array_a[1] = 1 -
对于
j从 0 到 9 -
结果:
f[2] = [2, 2, 0, 0, 0, 0, 0, 0, 0, 0]
-
-
第3个元素:
-
i = 3,array_a[2] = 1 -
对于
j从 0 到 9 -
结果:
f[3] = [4, 4, 0, 0, 0, 0, 0, 0, 0, 0]
-
返回结果
return f[n][B]
- 返回
f[3][2],即前3个元素中,一组和的个位数为2的划分方式数。 - 结果:
f[3][2] = 3
详细解释
-
初始状态:
f[0][0] = 1,表示没有任何元素时,和为 0 的划分方式数为 1。
-
第一个元素:
f[1][0] = 1:不选第一个元素,和为 0。f[1][1] = 1:选第一个元素,和为 1。
-
第二个元素:
f[2][0] = 2:不选第二个元素,和为 0;选第二个元素,和为 1。f[2][1] = 2:不选第二个元素,和为 1;选第二个元素,和为 2。
-
第三个元素:
f[3][0] = 4:不选第三个元素,和为 0;选第三个元素,和为 1。f[3][1] = 4:不选第三个元素,和为 1;选第三个元素,和为 2。f[3][2] = 3:不选第三个元素,和为 2;选第三个元素,和为 3。