[BZOJ4709] [Jsoi2011] 柠檬
[BZOJ4709] [Jsoi2011] 柠檬
用斜率优化维护转移,每次转移只转移当前点的颜色,这一定最优
注意斜率优化的查询不具有单调性,顾要用单调栈+二分维护
由于有多种颜色,我用一个\(vector\)来维护多个单调栈
const int N=1e5+10,P=1e9+7;
int n;
int a[N];
ll s[N];
#define chk(a,b) ((a<b)&&(a=b))
int cnt[N];
ll dp[N];
struct Node {
ll a,b;
};
vector <Node> G[N];
int main(){
n=rd();
rep(i,1,n) {
int x=rd();
int &c=cnt[x];
ll w=1ll*c*c*x+dp[i-1];
while(G[x].size()>1 && (G[x][G[x].size()-1].b-G[x][G[x].size()-2].b)*(c-G[x][G[x].size()-1].a) < (w-G[x][G[x].size()-1].b)*(G[x][G[x].size()-1].a-G[x][G[x].size()-2].a) ) G[x].pop_back(); // 单调栈
G[x].push_back((Node){c,w});
c++;
int l=1,r=G[x].size()-1,res=0;
while(l<=r) {
int mid=(l+r)>>1;
if( (G[x][mid].b-G[x][mid-1].b)>=2*x*c*(G[x][mid].a-G[x][mid-1].a)) l=mid+1,res=mid;
else r=mid-1;
} // 二分
w=G[x][res].b-2ll*x*c*G[x][res].a+1ll*c*c*x;
dp[i]=max(dp[i-1],w);
}
printf("%lld\n",dp[n]);
}