題意
你有一支由 n n n 名預備役士兵組成的部隊,士兵從 1 1 1 到 n n n 編號,你要將他們拆分成若干特別行動隊調入戰場。出于默契的考慮,同一支特別行動隊中隊員的編號應該連續,即為形如 i , i + 1 , ? , i + k i, i + 1, \cdots ,i + k i,i+1,?,i+k的序列。所有的隊員都應該屬于且僅屬于一支特別行動隊。
編號為 i i i 的士兵的初始戰斗力為 x i x_i xi? ,一支特別行動隊的初始戰斗力 X X X 為隊內士兵初始戰斗力之和,即 X = x i + x i + 1 + ? + x i + k X = x_i + x_{i+1} + \cdots + x_{i+k} X=xi?+xi+1?+?+xi+k?。
通過長期的觀察,你總結出對于一支初始戰斗力為 X X X 的特別行動隊,其修正戰斗力 X ′ = a X 2 + b X + c X'= aX^2+bX+c X′=aX2+bX+c,其中 a , b , c a,~b,~c a,?b,?c 是已知的系數。 作為部隊統帥,現在你要為這支部隊進行編隊,使得所有特別行動隊的修正戰斗力之和最大。試求出這個最大和。
1 ≤ n ≤ 1 0 6 1 \leq n \leq 10^6 1≤n≤106, ? 5 ≤ a ≤ ? 1 -5 \leq a \leq -1 ?5≤a≤?1, ? 1 0 7 ≤ b , c ≤ 1 0 7 -10^7 \leq b,c \leq 10^7 ?107≤b,c≤107, 1 ≤ x i ≤ 100 1 \leq x_i \leq 100 1≤xi?≤100。
思路
先考慮樸素的 dp,令 f i f_i fi? 表示將前 i i i 個人分隊完畢的最大戰斗力,設:
s i = ∑ j = 1 i x i , z ( x ) = a x 2 + b x + c s_i=\sum_{j=1}^{i}x_i,\ z(x)=ax^2+bx+c si?=j=1∑i?xi?,?z(x)=ax2+bx+c
那么有:
f i = max ? j ∈ [ 1 , i ) { f j + z ( s i ? s j ) } f_i=\max_{j\in[1,i)}\left \{f_j+z(s_i-s_j)\right \} fi?=j∈[1,i)max?{fj?+z(si??sj?)}
去到了 Θ ( n 2 ) \Theta(n^2) Θ(n2) 級別。由上一篇題解的經驗,考慮使用斜率優化掉找 j j j 的 Θ ( n ) \Theta(n) Θ(n):
設有決策點 j 1 j1 j1 和 j 2 j2 j2 且 j 2 j2 j2 優于 j 1 j1 j1,那么:
f j 1 + z ( s i ? s j 1 ) ≤ f j 2 + z ( s i ? s j 2 ) f_{j1}+z(s_i-s_{j1})\le f_{j2}+z(s_i-s_{j2}) fj1?+z(si??sj1?)≤fj2?+z(si??sj2?)
f j 1 + a ( s i ? s j 1 ) 2 + b ( s i ? s j 1 ) ≤ f j 2 + a ( s i ? s j 2 ) 2 + b ( s i ? s j 2 ) f_{j1}+a(s_i-s_{j1})^2+b(s_i-s_{j1})\le f_{j2}+a(s_i-s_{j2})^2+b(s_i-s{j2}) fj1?+a(si??sj1?)2+b(si??sj1?)≤fj2?+a(si??sj2?)2+b(si??sj2)
f j 1 + a s i 2 + a s j 1 2 ? 2 a s i s j 1 + b s i ? b s j 1 ≤ f j 2 + a s i 2 + a s j 2 2 ? 2 a s i s j 2 + b s i ? b s j 2 f_{j1}+as_i^2+as_{j1}^2-2as_is_{j1}+bs_i-bs_{j1}\le f_{j2}+as_i^2+as_{j2}^2-2as_is_{j2}+bs_i-bs_{j2} fj1?+asi2?+asj12??2asi?sj1?+bsi??bsj1?≤fj2?+asi2?+asj22??2asi?sj2?+bsi??bsj2?
f j 1 ? f j 2 ? b s j 1 + b s j 2 + a s j 1 2 ? a s j 2 2 ≤ 2 a s i s j 1 ? 2 a s i s j 2 f_{j1}-f_{j2}-bs_{j1}+bs_{j2}+as_{j1}^2-as_{j2}^2\le 2as_is_{j1}-2as_is_{j2} fj1??fj2??bsj1?+bsj2?+asj12??asj22?≤2asi?sj1??2asi?sj2?
f j 1 ? f j 2 ? b ( s j 1 ? s j 2 ) + a ( s j 1 2 ? s j 2 2 ) ≤ 2 a s i ( s j 1 ? s j 2 ) f_{j1}-f_{j2}-b(s_{j1}-s_{j2})+a(s_{j1}^2-s_{j2}^2)\le 2as_i(s_{j1}-s_{j2}) fj1??fj2??b(sj1??sj2?)+a(sj12??sj22?)≤2asi?(sj1??sj2?)
因為 s j 1 < s j 2 s_{j1}<s_{j2} sj1?<sj2?,因而注意變號:
f j 1 ? f j 2 ? b ( s j 1 ? s j 2 ) + a ( s j 1 2 ? s j 2 2 ) 2 a ( s j 1 ? s j 2 ) ≥ s i \frac{f_{j1}-f_{j2}-b(s_{j1}-s_{j2})+a(s_{j1}^2-s_{j2}^2)}{2a(s_{j1}-s_{j2})}\ge s_i 2a(sj1??sj2?)fj1??fj2??b(sj1??sj2?)+a(sj12??sj22?)?≥si?
那就不妨拿個 g i = a s i 2 + b s i g_i=as_i^2+bs_i gi?=asi2?+bsi? 來代換了:
f j 1 ? f j 2 + g j 1 ? g j 2 2 a ( s j 1 ? s j 2 ) ≥ s i \frac{f_{j1}-f_{j2}+g_{j1}-g_{j2}}{2a(s_{j1}-s_{j2})}\ge s_i 2a(sj1??sj2?)fj1??fj2?+gj1??gj2??≥si?
斜率 s l o p e ≥ s i slope\ge s_i slope≥si?, s i s_i si? 單增,由下圖,扔到符合條件區間的尾巴去。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define dd double
const ll N=1e6+9,inf=0x3f3f3f3f;
ll n,a,b,c,x[N];
ll s[N],g[N],f[N],q[N];
ll _2(ll x)
{return x*x;
}
ll z(ll x)
{return a*_2(x)+b*x+c;
}
dd slope(ll j1,ll j2)
{return (dd)(f[j1]-f[j2]+g[j1]-g[j2])/(dd)(2*a*(s[j1]-s[j2]));
}
int main()
{scanf("%lld%lld%lld%lld",&n,&a,&b,&c);for(int i=1;i<=n;i++){scanf("%lld",&x[i]);s[i]=s[i-1]+x[i];g[i]=a*_2(s[i])-b*s[i];}memset(f,-inf,sizeof(f));ll hh=0,tt=0;f[0]=0;for(int i=1;i<=n;i++){while(hh<tt&&slope(q[hh],q[hh+1])<=s[i])hh++;//slope>s[i]單增,扔隊尾 f[i]=f[q[hh]]+z(s[i]-s[q[hh]]);while(hh<tt&&slope(q[tt],i)<slope(q[tt-1],q[tt]))tt--;q[++tt]=i;}printf("%lld",f[n]);return 0;
}