[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]); }