題面
因爲懶得調格式問題,直接丟傳送門吧。傳送門
解答
一道斜率優化的題,話說斜率優化裏面的平方都是來噁心人的額。
我們考慮寫出一個樸素的dp式子:
然後丟掉max符號,拆開括號得到
若決策優於,那麼用j-k可以的到以下式子:
進一步化簡,移項得到
然後使用單調隊列的維護以下就好了。特別注意一點,由於所以我們維護的是一個上凸殼。所以要在取出隊首的時候斜率的大小比較需要相反。代碼如下:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int MAXN = 1000100;
int read(){
int x = 0,f = 1;
char c = getchar();
while(c<'0'||c>'9'){if(c=='-')f = -1;c = getchar();}
while(c>='0'&&c<='9'){x = x*10+(c^48);c = getchar();}
return x*f;
}
long long dp[MAXN];
long long sum[MAXN];
long long a,b,c;
double slope(int j,int k){
return double(dp[j]+a*(sum[j])*(sum[j])-b*sum[j]-dp[k]-a*(sum[k])*(sum[k])+b*sum[k])/double(sum[j]-sum[k]);
}
int q[MAXN],head,tail;
int n;
int main(){
n = read(),a = read(),b = read(),c = read();
long long v;
for(int i = 1;i<=n;i++){v = read();sum[i] = sum[i-1]+v;}
head = tail = 1;
for(int i = 1;i<=n;i++){
while(head<tail&&slope(q[head],q[head+1])>=2*a*sum[i])head++;//尤其注意這裏的斜率比較問題
int j = q[head];
dp[i] = dp[j]+a*(sum[i]-sum[j])*(sum[i]-sum[j])+b*(sum[i]-sum[j])+c;
while(head<tail&&slope(i,q[tail])>slope(q[tail],q[tail-1]))tail--;
q[++tail] = i;
}
printf("%lld\n",dp[n]);
return 0;
}