bzoj 2086 单调栈

题意:给定n个正整数,再给出m个正整数k,对于每个k,可以有如下操作:每次选择一个大于k的正整数a[i],将a[i]减去1,选择a[i-1]或a[i+1]中的一个加上1。经过一定次数的操作后,求一个最长的连续子序列满足这个子序列的每个数都不小于k

注意此题判的时候不忽略行末空格_(:3 」∠)_

虽然操作很唬人,但是它最终要求是

一个连续的子序列满足每个数都不小于k  等价于 这个连续的子序列的平均值不小于k

如何维护?

我们把每个数都减去一个k再维护一个前缀和

那么我们满足条件的区间就是 区间[l,r] 满足 sum[r]-sum[l-1]>=0

我们只需要找到r、l即可

显然i<j 且 sum[i]<=sum[j] 时选i更优

那么我们对左端点维护一个单调栈

然后从n到1倒序枚举右端点

var
        n,m,x           :longint;
        ans             :array[0..55] of longint;
        sum             :array[0..1000010] of int64;
        a,z             :array[0..1000010] of longint;
        i               :longint;
procedure work(x,t:longint);
var
        i:longint;
        top:longint;
begin
   for i:=1 to n do sum[i]:=sum[i-1]+int64(a[i])-int64(x);
   top:=1; z[top]:=0;
   for i:=1 to n do
     if sum[i]<sum[z[top]] then
     begin
        inc(top);
        z[top]:=i;
     end;
   for i:=n downto 1 do
   begin
      while (top>0) and (sum[i]-sum[z[top]]>=0) do dec(top);
      if i-z[top+1]>ans[t] then ans[t]:=i-z[top+1];
   end;
end;

begin
   read(n,m);
   for i:=1 to n do read(a[i]);
   for i:=1 to m do
   begin
      read(x);
      work(x,i);
   end;
   for i:=1 to m-1 do write(ans[i],' ');writeln(ans[m]);
end.
——by Eirlys



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值