BZOJ3461 : Jry的时间表

fl[i]表示[1,i]操作一次,且在[j+1,i]处操作的最大值

1:把[j+1,i]改为b[i]:

  max(sum[j]+b[i]*(i-j))

=b[i]*i+max(-j*b[i]+sum[j])(0<=j<i)

由于j递增,-j递减,所以从右往左建立凸壳,查询时在凸壳上二分查找即可,时间复杂度$O(n\log n)$。

2:把[j+1,i]改为b[j]:

  max(sum[j]+b[j+1]*(i-j))

=max(b[j+1]*i+sum[j]-b[j+1]*j)(0<=j<i)

考虑分治,对[l,mid]按b[j+1]从小到大排序,然后斜率优化即可,时间复杂度$O(n\log^2n)$。

将a,b序列翻转,即可求出fr[i]。

ans=max(fl[i]-sum[i]+fr[j]+sum[j-1])(0<=i<j<=n)

     =max(fr[j]+sum[j-1]+max(fl[i]-sum[i]))

维护前缀最大的fl[i]-sum[i]即可。

 

#include<cstdio>
#include<algorithm>
#define N 500010
typedef long long ll;
int n,i,j,a[N],b[N],c[N],e[N],q[N],h,t;ll sum[N],d[N],f[N],fl[N],fr[N],pre,ans;
inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
inline double pos(int x,int y){return (double)(sum[x]-sum[y])/(double)(x-y);}
inline ll ask(int x){
  int l=1,r=t-1,fin=t,mid;
  while(l<=r){
    mid=(l+r)>>1;
    if((double)x>pos(q[mid],q[mid+1]))r=(fin=mid)-1;else l=mid+1;
  }
  return sum[q[fin]]-(ll)q[fin]*x;
}
inline void up(ll&x,ll y){if(x<y)x=y;}
inline bool cmp(int x,int y){return c[x]==c[y]?d[x]>d[y]:c[x]<c[y];}
inline double slope(int x,int y){return (double)(d[x]-d[y])/(double)(c[y]-c[x]);}
void solve(int l,int r){
  if(l==r)return;
  int mid=(l+r)>>1;
  solve(l,mid),solve(mid+1,r);
  for(j=0,i=l;i<=mid;i++)e[j++]=i;
  for(std::sort(e,e+j,cmp),t=i=0,h=1;i<j;i++){
    if(i&&c[e[i]]==c[e[i-1]])continue;
    while(t>1&&slope(q[t-1],q[t])>=slope(q[t],e[i]))t--;
    q[++t]=e[i];
  }
  for(i=mid+1;i<=r;i++){
    while(h<t&&(d[q[h]]-d[q[h+1]])<=(ll)i*(c[q[h+1]]-c[q[h]]))h++;
    up(f[i],(ll)c[q[h]]*i+d[q[h]]);
  }
}
void work(){
  for(i=1;i<=n;i++)sum[i]=sum[i-1]+a[i];
  for(t=i=0;i<=n;q[++t]=i++){
    if(i)f[i]=(ll)b[i]*i+ask(b[i]);
    while(t>1&&pos(i,q[t])>pos(q[t],q[t-1]))t--;
  }
  for(i=0;i<n;i++)c[i]=b[i+1],d[i]=sum[i]-(ll)b[i+1]*i;
  solve(0,n);
}
int main(){
  for(read(n),i=1;i<=n;i++)read(a[i]);
  for(i=1;i<=n;i++)read(b[i]);
  work();
  for(i=1;i<=n;i++)fl[i]=f[i];
  for(i=1,j=n;i<j;i++,j--)t=a[i],a[i]=a[j],a[j]=t,t=b[i],b[i]=b[j],b[j]=t;
  work();
  for(i=1;i<=n;i++)fr[n-i+1]=f[i];
  for(i=1;i<=n;i++)sum[i]=sum[i-1]+a[n-i+1];
  for(ans=sum[n],i=1;i<=n;i++){
    up(ans,fr[i]+sum[i-1]+pre);
    up(pre,fl[i]-sum[i]);
  }
  return printf("%lld",ans),0;
}

  

posted @ 2015-07-04 14:57  Claris  阅读(444)  评论(0编辑  收藏  举报