2518. 好分区的数目

112 阅读2分钟

题目:
给你一个正整数数组 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
}