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;

}

  

你可能感兴趣的:(ZOJ)