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; }