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; }