jzoj. 3521. 【NOIP2013模拟11.7B组】道路覆盖(cover)

Description

ar把一段凹凸不平的路分成了高度不同的N段,并用H[i]表示第i段高度。现在Tar一共有n种泥土可用,它们都能覆盖给定的连续的k个部分。

对于第i种泥土,它的价格为C[i],可以使得区间[i,min(n,i+k-1)] 的路段的高度增加E[i]。

Tar要设定一种泥土使用计划,使得使用若干泥土后,这条路最低的高度尽量高,并且这个计划必须满足以下两点要求:

(1)每种泥土只能使用一次。

(2)泥土使用成本必须小于等于M。

请求出这个最低的高度最高是多少。

Input

第一行为如上文所示的三个正整数:N,M,K。

接下来N行,每行3个如上文所示的正整数H[i],E[i],C[i]。

Output

输出有且只有一个数字,为最底部分的高度的最大值

Sample Input

4 20 1

1 3 5

1 7 3

4 6 9

3 5 13

Sample Output

3

Data Constraint

对于30%的数据:N≤20。

对于100%的数据:1≤K≤11,1≤N≤100,0≤M,H[i],E[i],C[i]≤1000000。

分析:
一看题目,最小值最大,就知道应该是二分逼近求解,关键时看当前的值是否可以满足条件,也就是对于高度high,能否用m的钱把所有都增加到high及以上高度。这个判断要用dp完成(考试是愣是想不出来)。
设f[i,s]为把前i个部分升到high,i前面k个部分选取状态为s时的最小花费。
sum[i,s]也是前i个部分升到high,i前面k个部分选取状态,前面k个可以为i这个部分增加的高度。
因为一个点的状态之和他前面的k个部分有关,不需要记录所有状态。
当前点的状态s,只能由两个点转移过来,即
d和d+2^(k-1) {d=s shr 1}
(如:01这个状态,说明前一个数没有选,则是由00或10转移过来)

如果s为偶数,也就是当前点不用,有
f[i,s]=min(f[i-1,d],f[i-1,d+2^(k-1)]);
sum[i,s]=sum[i-1,d];

如果s为奇数,则当前点要选用,有
f[i,s]=min(f[i-1,d],f[i-1,d+2^(k-1)])+w[i] (w[i]为使用i的花费)
sum[i,s]=sum[i-1,d]+v[i] (v[i]为可以为i这个部分增高的高度)

当然,我们对于每个状态都有判断该状态下的sum[i,s]+h[i]>=high是否成立,h[i]为i部分开始高度,若不成立,则该状态不合法,把f[i,s]变为maxlongint即可。

最后判断f[n,s]中是否有一个状态是花费小于等于m的,如果有,则该高度可以达到。

代码:

var
 f,sum:array [0..101,0..2100] of longint;
 h,w,v:array [-11..101] of longint;
 n,m,k,i,j,l,r,ans,mid:longint;

function min(x,y:longint):longint;
 begin
  if x>y then exit(y)
         else exit(x);
 end;

function max(x,y:longint):longint;
 begin
  if x>y then exit(x)
         else exit(y);
 end;

procedure init;
var i,j:longint;
 begin
  for i:=0 to 101 do
   for j:=0 to 2100 do
    begin
     f[i,j]:=maxlongint div 3;
     sum[i,j]:=-maxlongint div 3;
    end;
 end;
function dp(high:longint):boolean;
 var i,j:longint;
     s,d,e,q:longint;
begin
 init;
 sum[0,0]:=0;
 f[0,0]:=0;
 d:=1 shl k-1;
 q:=1 shl (k-1);
 for i:=1 to n do
  begin
   for s:=0 to d do
    begin
     e:=s shr 1;
     if s mod 2=0 then
      begin
       f[i,s]:=min(f[i-1,e],f[i-1,e+q]);
       sum[i,s]:=max(sum[i-1,e],sum[i,s]);
       if sum[i,s]+h[i]<high then f[i,s]:=maxlongint div 3;
      end
     else
      begin
       f[i,s]:=min(f[i-1,e],f[i-1,e+q])+w[i];
       sum[i,s]:=max(sum[i-1,e]+v[i],sum[i,s]);
       if sum[i,s]+h[i]<high then f[i,s]:=maxlongint div 3;
      end;
    end;
  end;
 for s:=0 to d do
  if f[n,s]<=m then exit(true);
 exit(false);
end;

begin
 assign(input,'cover.in');
 assign(output,'cover.out');
 reset(input);
 rewrite(output);
 readln(n,m,k);
 for i:=1 to n do
   readln(h[i],v[i],w[i]);
 l:=0; r:=maxlongint;
 while l<=r do
  begin
   mid:=(l+r) shr 1;
   if dp(mid) then
     begin
      l:=mid+1;
      if mid>ans then ans:=mid;
     end
    else
     r:=mid-1;
  end;
 writeln(ans);
close(input);
close(output);
end.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
noip2013普及初赛是全国信息学奥林匹克联赛的一场选拔赛。该比赛旨在选拔初学者,对编程和算法有一定基础的学生,通过比赛形式来考察他们的知识水平和解题能力。 比赛题目通常会涉及各个领域的算法和数据结构,如图论、动态规划、数论等。题目难度逐步增加,从简单的输出结果,到复杂的程序设计与代码实现,考察选手的逻辑思维和编程能力。 参赛选手需要通过自己的思考和编程实现来解决题目,同时时间也是一个重要因素。比赛中,选手需要在规定的时间内独立完成所有题目,对于复杂的题目需要迅速想出解题思路并进行编码。因此,在比赛中,选手的临场发挥和解题速度也是需要考虑的因素。 noip2013普及初赛的结果将作为选拔阶段的一个重要依据,选出表现出色的选手进入到更高阶段的比赛,对于他们来说,这是一次展示自己实力的机会。 此外,noip2013普及初赛,也给了参赛选手一个交流的平台。选手们可以通过比赛结交同好,相互切磋,共同进步。同时,比赛结束后,还有详细的解题分析和讲解,有助于参赛选手对自己在比赛中的不足进行反思与改进。 总之,noip2013普及初赛是一个考察学生编程和算法能力的选拔赛,通过比赛的形式来选拔出优秀的选手。这对于参赛选手来说,是一次展示自己才华的机会,也是一个展示自己实力和提高自己能力的平台。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值