把一个包含n个正整数的序列划分成m个连续的子序列。设第i个序列的各数之和为S(i),求所有S(i)的最大值的最小值是多少?例如序列1 2 3 2 5 4划分为3个子序列的最优方案为 1 2 3 | 2 5 | 4,其中S(1),S(2),S(3)分别为6,7,4,最大值为7;如果划分为1 2 3|2|5 4,最大值为9,不是最小。
问题分析:能否使m个连续的子序列的和S(i)<=x,(i=1,2..m),则满足命题的最小x即为所求,可以采用贪心法,从左到右尽可能多的划分元素,可以把问题转化为递归分治问题,采用2分法,取n个正整数的和与n个正整数的最大值的中值x,若命题成立,则所求解小于等于x,若命题不成立,所求解大于x,2分递推求解,时间复杂度为O(n*logSum);
代码如下:
-
#include<iostream>
using namespace std;
const int MAX=100;
int a[MAX];
int n,m;bool Judge(int x)
{
int s=0,cnt=0;
for(int i=0;i<n;i++)
{
if(x<a[i])
return false;
if(s+a[i]<=x)
s+=a[i];
else
{
s=a[i];
cnt++;
if(cnt>m-1)
return false;
}
}
return true;
}int Solve(int lo,int hi)
{
int mid;
while(lo<hi)
{
mid=lo+(hi-lo)/2;
if(Judge(mid))
hi=mid;
else
lo=mid+1;
}
return lo;
}int main()
{
int max,sum,T;
cin>>T;
while(T--)
{
cin>>n>>m;
if(m>n)
m=n;
max=0;
sum=0;
for(int i=0;i<n;i++)
{
cin>>a[i];
if(max<a[i])
max=a[i];
sum+=a[i];
}
cout<<Solve(max,sum)<<endl;
}
return 0;
}
浙公网安备 33010602011771号