题目描述
longpo最近很忙,幸好他有很多得力的学生帮他分担工作。现在有n个工作,需要分配给m (m<=n)个人。longpo有一张工作表,a1, a2, … , an分别代表了这n个工作完成所需要的时间。为了方便,longpo给m个学生分配工作时,将连续一段ai—aj (1<= i <= j<= n)工作分配给每个人,每个学生都至少分到一个工作。工作的完成时间,由最晚完成的工作决定的,如有5个工作,每个工作完成的时间分别需要100, 100, 100, 100, 100,现在有4个同学做,那么可以如下分配:
100 / 100 / 100 / 100 100
前三个学生需要100的时间完成,第四个学生需要200的时间完成,那么全部工作完成的时间就是200。longpo希望完成工作的时间越少越少,那么由你帮忙给longpo决策,怎样分配工作。
输入
首先输入n, m
然后输入n个工作所需要的时间
输出
使用”/”将n个工作时间划分成m份,使得总的工作时间最少。方案有多种时,优先保证第一个人分配的工作最少,其次第二个人分配的工作最少……以此类推。
具体格式见样例。
样例输入
9 3
100 200 300 400 500 600 700 800 900
样例输出
100 200 300 400 500 / 600 700 / 800 900
提示
样例2
5 4
100 100 100 100 100
样例2
100 / 100 / 100 / 100 100
对于30%的数据 1<=m<=n<=30, 1<=ai<=10^3
对于60%的数据1<=m<=n<=100, 1<=ai<=10^5
对于100%的数据1<=m<=n<=500, 1<=ai<=10^8
相信大家都能判断出工作时间需要二分求解,但是此题恶心的是需要划分方案,一时让人摸不着头脑。
后来我想了这样一个方法,我们先对n个工作进行分段,使每段都达到最大,并在相应位置标记(为了输出斜杠)。然后如果离m人还差几段,就从头开始扫,如果某个位置没有标记,就再分一段,输出斜杠,这样就可以保证头里的人工作时间最少。
#include<cstdio>
#include<iostream>
#define ll long long
using namespace std;
int a[505],b[505];
int n,m;
ll sum,ans,now,maxv;
ll erfen(ll l,ll r)
{
if(l>r) return l;
ll mid=(l+r)/2;
int k=0;
int ok=0;
ll s=0;
for(int i=n;i>=1;i--)
if(s+a[i]>mid)
{
k++;
s=a[i];
}
else s=s+a[i];
if(s>0) k++;
if(k>m) return erfen(mid+1,r); else return erfen(l,mid-1);
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
maxv=max(maxv,(ll)(a[i]));
sum=sum+a[i];
}
ans=erfen(maxv,sum);
now=0;
int k=1;
for(int i=n;i>=1;i--)
if(now+a[i]>ans)
{
b[i]=1;
k++;
now=a[i];
}
else now=now+a[i];
for(int i=1;i<n;i++)
{
printf("%d ",a[i]);
if(b[i]==1) printf("/ ");
if(b[i]==0&&k<m)
{
k++;
printf("/ ");
}
}
printf("%d\n",a[n]);
return 0;
}