📅  最后修改于: 2023-12-03 15:37:08.968000             🧑  作者: Mango
在算法竞赛中,往往需要处理数组的子集问题。而对于某些需要满足一定限制才算合法的子集问题,我们常常可以使用二分答案的思路来解决。本文就将介绍如何对于给定的一个数组,将其最多能划分成多少个和至少为k的子集。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n,K,x,ans,mx,a[N],cnt;
inline bool check(int mid){
cnt = 1; int sum = a[1];
for(int i = 2;i <= n;++i){
if(a[i] > mid) return 0;
if(sum + a[i] <= mid) sum += a[i];
else sum = a[i],++cnt;
}
return cnt <= K;
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin >> n >> K;
for(int i = 1;i <= n;++i){
cin >> a[i];
mx = max(mx,a[i]);
x += a[i];
}
int l = mx,r = x,res =-1;
while(l <= r){
int mid = (l + r) >> 1;
if(check(mid)) res = mid,ans = mid,r = mid - 1;
else l = mid + 1;
}
cout << ans;
return 0;
}
假设数组为 $a_1,a_2,\ldots,a_n$,我们可以考虑使用二分答案的思路,假设当前二分的答案为 $mid$,我们需要确定是否存在一种划分方案,使得可以将数组分成 $K$ 个子集,每个子集的和都不小于 $mid$。故在 check-mid 中可以按照以下的思路进行划分:
最终,如果我们能够划分出不多于 $K$ 个大小至少为 $mid$ 的子集,则说明答案可以更小一些;否则,答案必须更大一些。
具体的详细解释可以见代码注释。