软件公司

题意

给你两种不同的工作,而每一项工作有m份。一共有n个人工作,且每个人工作两种不同的工作时间为 xi,yi ,问最小的时间是多少?(每个子项目必须由一个人一次完成,多个人可以同时做同一个项目中的不同子项目)

数据范围

对于30%的数据,n<=30.
对于60%的数据,n<=60.
对于100%的数据, n,m<=100.

分析

首先这题我们可以列出最基本的 dp 方程: f[i,j,k]=max(f[i1,js,kt],sA[i]+tB[i]) 表示第 i 个人做了j份第一项工作, k 份第二项工作。明显的这样会超时O(nm4),只能过30分数据。那么我们就要从另一个角度去思考优化。我们可以从方程或题意得出这题让我们求的是每个人工作的时间的最大值最小值。咦,这不是二分吗?对!二分大法!我们就要往判定去想了,判定是判定能否在规定时间内做m份工作,这时我们很明显想到用 f[i,j,k] 表示能否完成,但是这样是不能从本质去解决问题的,那么就只能降维,转成 f[i,j] ,没错可以!用 f[i,j] 照样可以表示, f[i,j] 代表到前i个人,在1项目做了j个的情况下,2项目能做的最多的个数。转移为: f[i,j]=max(f[i,j],f[i1,jk]+(anskA[i])/B[i]) 最后就直接判断 f[n,m] 是否>=m即可。

注意

要初始化,否则会出错!

总结

这题的思想归根结底还是二分,但是方程的优化是巧妙的,能又三维转成二维。

var
    n,m,l,r,ma,i,mid:longint;a:array[1..190,1..2] of longint;f:array[0..100,0..100] of longint;
function max(l,r:longint):longint;
begin
    if l<r then exit(r) else exit(l);
end;
function check(x:longint):boolean;
var i,j,k:longint;
begin
    for i:=0 to n do
        for j:=0 to m do f[i,j]:=-maxlongint;
    f[0,0]:=0;
    for i:=1 to n do
       for j:=0 to m do
           for k:=0 to j do begin
              if x-k*a[i,1]<0 then break;
              f[i,j]:=max(f[i,j],f[i-1,j-k]+(x-k*a[i,1]) div a[i,2]);
              x:=x;
           end;
    if f[n,m]>=m then exit(true);exit(false);
end;
begin
assign(input,'company.in');reset(input);
assign(output,'company.out');rewrite(output);
    readln(n,m);
    for i:=1 to n do begin read(a[i,1],a[i,2]);ma:=max(max(ma,a[i,2]),a[i,1]);end;
    l:=0;r:=ma*n;
    while l<r do begin
       mid:=(l+r)shr 1;
       if check(mid) then r:=mid else l:=mid+1;
    end;
    writeln(l);
close(input);close(output);
end.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值