Luo 1233 工作分配

题目描述

longpo最近很忙,幸好他有很多得力的学生帮他分担工作。现在有n个工作,需要分配给m (m<=n)个人。longpo有一张工作表,a1, a2, … , an分别代表了这n个工作完成所需要的时间。为了方便,longpo给m个学生分配工作时,将连续一段aiaj (1<= i <= j<= n)工作分配给每个人,每个学生都至少分到一个工作。工作的完成时间,由最晚完成的工作决定的,如有5个工作,每个工作完成的时间分别需要100, 100, 100, 100, 100,现在有4个同学做,那么可以如下分配:

100 / 100 / 100 / 100 100

    前三个学生需要100的时间完成,第四个学生需要200的时间完成,那么全部工作完成的时间就是200。longpo希望完成工作的时间越少越少,那么由你帮忙给longpo决策,怎样分配工作。

输入

首先输入nm

然后输入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;
}



















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值