P3628 [APIO2010] 特别行动队

//URL: https://www.luogu.com.cn/problem/P3628
/*
你有一支由 nn 名预备役士兵组成的部队,士兵从 11 到 nn 编号,你要将他们拆分成若干特别行动队调入战场。出于默契的考虑,同一支特别行动队中队员的编号应该连续,即为形如 (i,i+1,⋯i+k)(i,i+1,⋯i+k)的序列。所有的队员都应该属于且仅属于一支特别行动队。
编号为 ii 的士兵的初始战斗力为 xixi​ ,一支特别行动队的初始战斗力 XX 为队内士兵初始战斗力之和,即 X=xi+xi+1+⋯+xi+kX=xi​+xi+1​+⋯+xi+k​。
通过长期的观察,你总结出对于一支初始战斗力为 XX 的特别行动队,其修正战斗力 X′=aX2+bX+cX′=aX2+bX+c,其中 a, b, ca, b, c 是已知的系数
(a<0a<0)。 作为部队统帅,现在你要为这支部队进行编队,使得所有特别行动队的修正战斗力之和最大。试求出这个最大和

dp[i]=max(dp[j]+a*(s[i]-s[j])^2+b*(s[i]-s[j])+c)
dp[i]=max(dp[j]+a*s[j]^2-2*a*s[i]*s[j]-b*s[j])+a*s[i]^2+b*s[i]+c
2*a*s[i]*s[j]+dp[i]-a*s[i]^2-b*s[i]-c=dp[j]+a*s[j]^2-b*s[j]
  Ki*Xj        +Bi = Yj
Ki -- 要Bi最大  维护上凸包 斜率DP
head:>Ki head++
tail: 不单调增 tail--

*/
/*
4 
-1 10 -20 
2 2 3 4 

9
*/
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<string.h>
#include<queue>
#include<vector>
#include<bits/stdc++.h>
typedef long long ll;
#define ddd printf("-----------------------\n");
using namespace std;
const int maxn=1e6 +10;
const int mod=998244353;
const int inf=0x3f3f3f3f;


#define k(A) (2*a*s[A])
#define x(A) s[A]
#define b(A) (dp[A]-a*s[A]*s[A]-b*s[A]-c)
#define y(A) (dp[A]+a*s[A]*s[A]-b*s[A])

ll dp[maxn],s[maxn];
int q[maxn],n,a,b,c;
double xie(int i,int j){
    return 1.0*(y(i)-y(j))/(x(i)-x(j));
}

int main()
{
    ios::sync_with_stdio(false);
    cin>>n>>a>>b>>c;
    //cout<<n<<a<<b<<c<<endl;
    for(int i=1;i<=n;i++){
        int x;cin>>x; //cout<<x<<endl;
        s[i]=s[i-1]+x;
        //cout<<s[i]<<'\n';
    }
    int head=1,tail=0;q[++tail]=0;dp[0]=0;
    for(int i=1;i<=n;i++){
        while(head<tail&&xie(q[head],q[head+1])>k(i)) head++;
        dp[i]=-(k(i)*x(q[head])-y(q[head])-a*s[i]*s[i]-b*s[i]-c);
        while(head<tail&&xie(q[tail-1],q[tail])<=xie(q[tail],i)) tail--;
        q[++tail]=i;
    }
    cout<<dp[n]<<endl;
    return 0;
}

 

posted @ 2023-12-25 04:23  JMXZ  阅读(13)  评论(0)    收藏  举报