[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]);
}
 
posted @ 2019-10-26 14:44  chasedeath  阅读(140)  评论(0编辑  收藏  举报