题目
题目链接:https://codeforces.com/problemset/problem/660/F
给一个长度为 (n) 的序列 (a),选一个区间 ([l,r]) 使得 (sum^{r}_{i=l}(i-l+1) imes a_i) 最大。
(nleq 2 imes 10^5)。
思路
记 (f_i) 为 (a) 的前缀和,(g_i=sum^{i}_{j=1}j imes a_j)。那么
[ans_j=max_{0leq i<j}(g_j-g_i-i imes (f_j-f_i))
]
维护一个上突壳,二分斜率即可。
时间复杂度 (O(nlog n))。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=200010;
int n,top,q[N];
ll ans,f[N],g[N],X[N],Y[N];
double slope(int i,int j)
{
return 1.0*(Y[i]-Y[j])/(X[i]-X[j]);
}
int binary(double k)
{
int l=2,r=top,mid;
while (l<=r)
{
mid=(l+r)>>1;
if (slope(q[mid],q[mid-1])>=k) l=mid+1;
else r=mid-1;
}
return q[l-1];
}
int main()
{
scanf("%d",&n);
for (int i=1,x;i<=n;i++)
{
scanf("%d",&x);
f[i]=f[i-1]+x; g[i]=g[i-1]+1LL*x*i;
X[i]=i; Y[i]=1LL*i*f[i]-g[i];
}
q[++top]=0;
for (int i=1;i<=n;i++)
{
int j=binary(f[i]);
ans=max(ans,g[i]-g[j]-1LL*j*(f[i]-f[j]));
while (top>1 && slope(q[top-1],q[top])<=slope(q[top],i)) top--;
q[++top]=i;
}
cout<<ans;
return 0;
}