[Educational Round 59][Codeforces 1107G. Vasya and Maximum Profit]

咸鱼了好久...出来冒个泡_(:з」∠)_

题目连接:1107G - Vasya and Maximum Profit

题目大意:给出\(n,a\)以及长度为\(n\)的数组\(c_i\)和长度为\(n\)的严格单调上升数组\(d_i\),求\(\max\limits_{1 \le l \le r \le n} (a\cdot(r-l+1)-\sum_{i=l}^{r}c_i-gap(l,r))\),其中\(gap(l, r) = \max\limits_{l \le i < r} (d_{i + 1} - d_i)^2\)

题解:首先将所有的\(c_i\)转换为\(a-c_i\),这样就变成了求\(\max\limits_{1 \le l \le r \le n} (\sum_{i=l}^{r}c_i-gap(l,r))\)。如果\(l,r\)确定的话,我们就能通过求前缀和以及区间内最大值来算出该区间对应的答案,但我们还需要进一步的优化。

  考虑每一个\(d_{i + 1} - d_i\)能成为\(gap(l,r)\)的范围,即在区间\([L,R]\)中,\(\forall L \le l \le r \le R,gap(l,r)\le d_{i + 1} - d_i\)。这样我们只需要用线段树查询区间\([L,R]\)的最大子段和就能求出当\(gap(l,r) \le d_{i + 1} - d_i\)时的答案。先预处理所有的\(L,R\),再扫一遍就好了。

#include<bits/stdc++.h>
using namespace std;
#define N 300001
#define LL long long
LL n,b,l[N],r[N],a[N],d[N],L,R,M,S,ans;
struct rua{LL l,r,w,s,lw,rw;}t[N<<2];
void up(int x,int mid)
{
    t[x].s=t[x*2].s+t[x*2+1].s;
    t[x].w=max(t[x*2].w,t[x*2+1].w);
    t[x].lw=max(t[x*2].lw,t[x*2].s+t[x*2+1].lw);
    t[x].rw=max(t[x*2+1].rw,t[x*2+1].s+t[x*2].rw);
    t[x].w=max(t[x].w,t[x*2].rw+t[x*2+1].lw);
}
void Build(int l,int r,int x)
{
    t[x].l=l,t[x].r=r;
    if(l==r){t[x].w=t[x].lw=t[x].rw=t[x].s=a[l];return;}
    int mid=l+r>>1;
    Build(l,mid,x*2);
    Build(mid+1,r,x*2+1);
    up(x,mid);
}
void ask(int ll,int rr,int l,int r,int x)
{
    if(ll>r || l>rr)return;
    int mid=l+r>>1;
    if(ll<=l && r<=rr)
      {
      M=max(M,max(t[x].w,R+t[x].lw));
      L=max(L,S+t[x].lw);
      R=max(R+t[x].s,t[x].rw);
      M=max(M,max(L,R));
      S+=t[x].s;
      return;
      }
    ask(ll,rr,l,mid,x*2);
    ask(ll,rr,mid+1,r,x*2+1);
}
int main()
{
    scanf("%I64d%I64d",&n,&b);
    for(LL i=1;i<=n;i++)
      {
      scanf("%I64d%I64d",&d[i],&a[i]);
      a[i]=b-a[i],ans=max(ans,a[i]);
      }
    for(LL i=n;i>=1;i--)d[i]-=d[i-1];
    Build(1,n,1);
    d[1]=0;
    l[2]=2,r[n]=n;
    for(LL i=3;i<=n;i++)
      {
      LL _=i;
      while(_>2 && d[i]>=d[_-1])
        _=l[_-1];
      l[i]=_;
      }
    for(LL i=n-1;i>=2;i--)
      {
      LL _=i;
      while(_<n && d[i]>=d[_+1])
        _=r[_+1];
      r[i]=_;
      }
    for(LL i=2;i<=n;i++)
      {
      S=0;
      L=R=M=-(1e18);
      ask(l[i]-1,r[i],1,n,1);
      ans=max(ans,M-d[i]*d[i]);
      }
    printf("%I64d\n",ans);
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/DeaphetS/p/10326785.html
今日推荐