最大值最小化问题,由于是一个单峰函数,可以用二分求出最小值来,然后从后往前划分,使后面的划分尽可能大,这样能保证题目所要求的S(1)尽量小。
#include<cstdio>
#include<algorithm>
#include<cstring>
#define LL long long
using namespace std;
const int maxn = 10000000+10;
int num[maxn],n,k,bj[maxn];
LL maxx,minn;
int solve(LL mid)
{
int flag=1,cnt=0;
LL sum =0;
for(int i=n; i>0; i--)
{
if(num[i]>mid)
{
flag=0;
break;
}
else if(sum+num[i]<=mid)
sum+=num[i];
else if(sum+num[i]>mid)
{
sum=num[i];
cnt++;
if(cnt>k-1)
{
flag=0;
break;
}
}
}
return flag;
}
int bisearch()
{
LL l=minn,r=maxx;
while(l<r)
{
LL mid=l+(r-l)/2;
if(solve(mid))r=mid;
else l=mid+1;
}
return l;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
memset(bj,0,sizeof(bj));
memset(num,0,sizeof(num));
minn=maxn;
scanf("%d %d",&n,&k);
for(int i=1; i<=n; i++)
{
scanf("%d",&num[i]);
if(minn>num[i])minn=num[i];
maxx+=num[i];
}
LL p=bisearch();
LL temp=0;
int js=k-1;
for(int i=n; i>0; i--)
{
if(js<i)
{
if(temp+num[i]<=p)
temp+=num[i];
else
{
temp=num[i];
bj[i]=1;
js--;
}
}
else
bj[i]=1;
}
for(int i=1; i<=n; i++)
{
if(i!=n)
{
printf("%d ",num[i]);
if(bj[i])printf("/ ");
}
else
printf("%d\n",num[i]);
}
}
return 0;
}