给你一个序列,把它划分成若干个子序列,要求子序列和最大值最小。
用check(x)来检查是否能使所有子序列的和都不大于x,在检查的同时进行划分和记录。
然后二分查找,下限是整数最大值,上限是序列所有整数的和。可以划分的话说明最大值可能是这个也可能更小,上限减小;不能划分说明值太小,下限增大。
整数和范围可能超过int,要用long long。
AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
ll m,k,a[510],b[510],ans[510],Left,Right,mid;
int check(ll maxx)
{
int num=0,tot=0;
memset(b,0,sizeof(b));
for(int j=m;j>=1;j--)
{
if(tot+a[j]<=maxx&&j>=k-num)
tot+=a[j];
else
{
++num;
tot=a[j];
b[j]=1;
}
}
if(num+1==k)
{
for(int j=1;j<=m;j++)
ans[j]=b[j];
return 1;
}
return 0;
}
int main()
{
int t;
cin>>t;
while(t--)
{
Left=0,Right=0;
scanf("%lld %lld",&m,&k);
for(int i=1;i<=m;i++)
{
scanf("%lld",&a[i]);
Right+=a[i];
Left=max(a[i],Left);
}
memset(ans,0,sizeof(ans));
while(Left<=Right)
{
mid=(Left+Right)/2;
if(check(mid)==1)
Right=mid-1;
else Left=mid+1;
}
for(int i=1;i<m;i++)
{
if(ans[i]==1)
printf("%lld / ",a[i]);
else printf("%lld ",a[i]);
}
cout<<a[m]<<endl;
}
return 0;
}