Number of Great Partitions

Number of Great Partitions

You are given an array nums consisting of positive integers and an integer k .

Partition the array into two ordered groups such that each element is in exactly one group. A partition is called great if the sum of elements of each group is greater than or equal to k .

Return the number of distinct great partitions. Since the answer may be too large, return it modulo 109+7.

Two partitions are considered distinct if some element nums[i] is in different groups in the two partitions.

Example 1:

Input: nums = [1,2,3,4], k = 4
Output: 6
Explanation: The great partitions are: ([1,2,3], [4]), ([1,3], [2,4]), ([1,4], [2,3]), ([2,3], [1,4]), ([2,4], [1,3]) and ([4], [1,2,3]).

Example 2:

Input: nums = [3,3,3], k = 4
Output: 0
Explanation: There are no great partitions for this array.

Example 3:

Input: nums = [6,6], k = 2
Output: 2
Explanation: We can either put nums[0] in the first partition or in the second partition.
The great partitions will be ([6], [6]) and ([6], [6]).

Constraints:

  • 1nums.length,k1000
  • 1nums[i]109

 

解题思路

  首先还是容易想到用动态规划的,定义f(i,j)表示所有从前i个数中凑出总和为j的方案的个数,根据第i个物品选或不选进行状态划分,那么状态转移方程就是f(i,j)=f(i1,j)+f(i1,jnums[i])。最后答案就是i=kskf(n,i),其中s是所有数的总和。

  可以发现s最大可以取到1012,因此这种做法的计算量可以达到1015级别。

  现在倒过来想,能不能求出所有“不好分区”的数目,然后用总的分区数目减去“不好分区”的数目来得到答案呢?当然可以,如果求“不好分区”的数目那么状态的第二维就可以控制到k以内,时间复杂度就降到了O(nk)了。

  为了方便下面用f(i)来表示f(n,i),即从前n个物品中凑出总和为i的方案的个数。

  “不好分区”分为3种情况:

  1. 1组的总和小于k,第2组的总和大于等于k
  2. 1组的总和大于等于k,第2组的总和小于k
  3. 1组和第2组的总和均小于k

  这里统一规定f(i)指的是第1组的总和,题目中这两个组明显是不可互换的,即 ([1,2,3], [4]) 和 ([4], [1,2,3]) 是两个不同的组。

  其中对于第12种情况,i要同时满足i<k以及sik,因此“不好分区”的个数都是i=0max{k1,sk}f(i),因此这两种的情况的总个数就是i=0max{k1,sk}2f(i)f(i)一个是放第1组,一个是放第2组)。

  对于第3种情况,i要同时满足i<k以及si<k,因此“不好分区”的个数是i=min{0,sk+1}k1f(i)

  最后因为每个物品可以选择放在第1组或第2组,有两种选择,因此总的分区数目是2n

  最终答案就是2n  i=0max{k1,sk}2f(i)  i=min{0,sk+1}k1f(i)

  AC代码如下:

复制代码
 1 class Solution {
 2 public:
 3     int mod = 1e9 + 7;
 4 
 5     int countPartitions(vector<int>& nums, int k) {
 6         int n = nums.size();
 7         vector<vector<int>> f(n + 1, vector<int>(k + 1));
 8         f[0][0] = 1;
 9         for (int i = 1; i <= n; i++) {
10             for (int j = 0; j <= k; j++) {  // 记得j从0开始,因为其中一组什么都不放也算是不合法的分区方案
11                 f[i][j] = f[i - 1][j];
12                 if (j >= nums[i - 1]) f[i][j] = (f[i][j] + f[i - 1][j - nums[i - 1]]) % mod;
13             }
14         }
15         int ret = 1;
16         long long s = 0;
17         for (int i = 0; i < n; i++) {
18             ret = ret * 2 % mod;
19             s += nums[i];
20         }
21         for (int i = 0; i < k; i++) {
22             long long t = s - i;    // 另外一组分区的总和
23             if (t >= k) ret = (ret - 2 * f[n][i] % mod) % mod;  // 第1、2种情况
24             else ret = (ret - f[n][i]) % mod;   // 第3种情况
25         }
26         return (ret + mod) % mod;
27     }
28 };
复制代码

 

参考资料

  计数 & 背包 dp:https://leetcode.cn/problems/number-of-great-partitions/solution/by-tsreaper-69ff/

posted @   onlyblues  阅读(21)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
Web Analytics
点击右上角即可分享
微信分享提示