BZOJ3024 : [Balkan2012]balls

问题1:

ans=max(sum[n]-(sum[i]-sum[j-1])+a[i]*(i-j+1))

=max(sum[n]-sum[i]+sum[j-1]+a[i]*(i+1)-a[i]*j)

=sum[n]-sum[i]+a[i]*(i+1)+f[i]

f[i]=max(-j*a[i]+sum[j-1]),j<i

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

问题2:

将序列翻转后即化为问题1。

 

#include<cstdio>
#define N 300010
typedef long long ll;
int n,i,j,a[N],q[N],t;ll sum[N],b[N],f[N],ans;
inline void read(int&a){
  char c;bool f=0;a=0;
  while(!((((c=getchar())>='0')&&(c<='9'))||(c=='-')));
  if(c!='-')a=c-'0';else f=1;
  while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';
  if(f)a=-a;
}
inline double pos(int x,int y){return (double)(b[x]-b[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 b[q[fin]]-(ll)q[fin]*x;
}
inline void up(ll x){if(ans<x)ans=x;}
void work(){
  for(ans=-1LL<<60,i=1;i<=n;i++)sum[i]=sum[i-1]+a[i],b[i]=sum[i-1];
  for(t=0,i=1;i<=n;q[++t]=i++){
    if(i>1)up(sum[n]-sum[i]+(ll)a[i]*(i+1)+ask(a[i]));
    while(t>1&&pos(i,q[t])>pos(q[t],q[t-1]))t--;
  }
  printf("%lld\n",ans);
}
int main(){
  for(read(n),i=1;i<=n;i++)read(a[i]);
  work();
  for(i=1,j=n;i<j;i++,j--)t=a[i],a[i]=a[j],a[j]=t;
  work();
  return 0;
}

  

posted @ 2015-07-03 22:29  Claris  阅读(438)  评论(0编辑  收藏  举报