题意:
把一个包含m个正整数的序列划分成k个非空的连续子序列,使得每个正整数恰好属于一个序列。
题解:
最大值尽量小是一种很常见的优化目标。二分法,right=序列总和,left=序列中的最大数。判断是否小于等于K个分发,否则left=mid+1,一直二分直至求到最小的最大值。
代码:
#include <iostream>
#include <cstring>
using namespace std;
typedef long long LL;
const int maxn = 500+5;
int vis[maxn];
LL m,k,data[maxn],l,r;
bool solve(LL sum)
{
int count=0;
LL s =0 ;
//cout<<sum<<" ";
for(int i=1;i<=m;i++)
{
if(s+data[i]<=sum)
s+=data[i];
else{
s=data[i];
count++;
}
}
count++;
//cout<<count<<endl;
if(count>k) return false;
return true;
}
void output()
{
memset(vis,0,sizeof(vis));
int count=1;
LL sum=0;
for(int i=m;i>=1;i--)
{
if(sum+data[i] <= l)
sum += data[i];
else{
count++;
sum =data[i];
vis[i]=1;
//cout<<i<<" "<<count<<endl;
}
}
for(int i=1;i<=m&&count<k;i++)
{
if(!vis[i])
{
vis[i]=1;
count++;
}
}
for(int i=1;i<m;i++)
{
cout<<data[i]<<" ";
if(vis[i]) cout<<"/ ";
}
cout<<data[m]<<endl;
}
int main()
{
int T;
cin>>T;
while(T--)
{
cin>>m>>k;
l=0,r=0;
for(int i=1;i<=m;i++){
cin>>data[i];
r+=data[i];
l = max(l,data[i]);
}
while(r>=l)
{
LL mid = (r+l)>>1;
if(solve(mid)) {r=mid-1;}
else l=mid+1;
}
output();
}
return 0;
}