题目:
把一个包含n个正整数的序列划分成m个连续的子序列(每个正整数恰好属于一个序列)。设第i个序列的各数之和为S(i),如何让所有S(i)的最大值尽量小?
例如序列1 2 3 2 5 4,划分成3个序列的最优方案为1 2 3 | 2 5 | 4,其中S(1)=6, S(2)=7, S(3)=4,最大值为7;如果划分成1 2 | 3 2 | 5 4,则最大值为9,不如刚才的好。
n≤106,所有数之和不超过109。
这个题目考查到二分查找
#include <iostream>
using namespace std;
int a[1000001];
int n,m,maxa,sum;
bool judge(int x) //把序列划分为子序列之和最大为x的m个子序列
{
int k=0,s=0;
for(int i=0;i<n;i++)
{
if(a[i]>x) //该项比x大
return false;
if(s+a[i]>x) //该子序列的总和比x大
{
k++;
if(k==m) return false;
s=a[i];
}
else s+=a[i]; //添加进子序列
}
return true;
}
int b_search()
{
int low=maxa,top=sum;
while(low<top)
{
int mid = (low+top)>>1; //位移1,相当于除2,位运算效率比较高
if(judge(mid))
top = mid; //能找到则top为mid,如果改为mid-1万一下面又找不到,就无法返回该值
else low = mid+1;
}
return low;
}
int main()
{
while(cin >> n>>m )
{
sum = maxa = 0;
for(int i=0;i<n;i++){ //找出数组中的最大数和总和
cin >> a[i];
sum += a[i];
if(maxa<a[i]) maxa=a[i];
}
cout<< b_search() <<endl;
}
return 0;
}