题目:
给你一个正整数数组 nums 和一个整数 k 。
分区 的定义是:将数组划分成两个有序的 组 ,并满足每个元素 恰好 存在于 某一个 组中。如果分区中每个组的元素和都大于等于 k ,则认为分区是一个好分区。
返回 不同 的好分区的数目。由于答案可能很大,请返回对 109 + 7 取余 后的结果。
如果在两个分区中,存在某个元素 nums[i] 被分在不同的组中,则认为这两个分区不同。
算法:
方法一:动态规划
dp[i][j]前i个元素之和小于等于j的分区个数
dp[i][j] = dp[i - 1][j]不选第i个数字
dp[i][j] = dp[i - 1][j - x]选第i个数字 (j>=x)
我们计算出不好的分区dp[n-1][k-1],然后将总的分区-不好的分区得到答案。总分区的数目:2^n。(归纳法)
计算不好的分区的方法:遍历dp[n-1],得到分区和为0~k-1的分区个数x。对每一个分区,计算是两个分区都小于k,还是只有一个分区小于k。
两个分区都小于k:坏分区数x。因为dp[i][j]的结果包含了dp[i][k-j]的结果
只有一个分区小于k:坏分区数2*x
func countPartitions(nums []int, k int) int {
n := len(nums)
MOD := 1000000007
dp := make([][]int, n + 1)
for i := range dp {
dp[i] = make([]int, k)
}
dp[0][0] = 1
sum := 0
ans := 1
for i := range nums {
sum = sum + nums[i]
ans = (ans * 2) % MOD
}
for i := 1; i <= n; i ++ {
x := nums[i - 1]
for j := 0; j < k; j ++ {
dp[i][j] = dp[i - 1][j]
if j >= x {
dp[i][j] = (dp[i][j] + dp[i - 1][j - x]) % MOD
}
}
}
for j := 0; j < k; j ++ {
delta := sum - j
if delta >= k {
ans = (ans - dp[n][j] * 2 % MOD + MOD) % MOD;
} else {
ans = (ans - dp[n][j] + MOD) % MOD;
}
}
return ans
}