分析
預處理前綴和
這顯然是dp。
設
則有:
①邊界條件:
②動態轉移方程:
③答案:
直接求解,時間複雜度爲
考慮斜率優化。
原來的方程太複雜了,我們先化簡一下。
通過換元法化簡動態轉移方程,將參量、變量、常量分離。
記
再求解斜率方程。
爲了加快求解,我們設法儘可能多的排除一些狀態,這需要決策點之間的比較,我們要找出決策點比較的式子。
設當前要求
不難發現,
近一步,
對於
①當
②當
可以將問題轉化爲平面上的點的問題。
現在問題轉化爲:
給定平面上
①插入點操作:
在第
②詢問點操作:
在點集
③更改
將
要尋找的點
又由於
我們只需要維護一個單調隊列即可。
隊首維護:
隊首的點爲
隊尾維護:
隊末三個點爲
若
每個點進隊一次,出隊一次。
所以總的時間複雜度爲
總結
總算徹底弄清斜率優化的嚴謹過程了。
代碼
#include <cstdio>
#include <cctype>
typedef long long Lint;
const int N=65536;
int n,l;
int c[N];
Lint sum[N];
Lint g[N];
Lint C;
Lint f[N];
Lint x[N];
Lint y[N];
int q[N];
int qh,qt;
inline int Read(void)
{
int x=0; char c=getchar();
for (;!isdigit(c);c=getchar());
for (;isdigit(c);c=getchar()) x=x*10+c-'0';
return x;
}
inline double Slope(int i,int j)
{
return ((double)y[i]-y[j])/(x[i]-x[j]);
}
int main(void)
{
n=Read(),l=Read();
for (int i=1;i<=n;i++) c[i]=Read();
for (int i=1;i<=n;i++) sum[i]=sum[i-1]+c[i];
C=1+l;
for (int i=1;i<=n;i++) g[i]=sum[i]+i;
f[0]=0;
x[0]=g[0];
y[0]=f[0]+(g[0]+C)*(g[0]+C);
q[qh=qt=1]=0;
for (int i=1;i<=n;i++)
{
for (;qh!=qt&&Slope(q[qh+1],q[qh])<=2.0*g[i];q[qh++]=0);
f[i]=f[q[qh]]+(g[i]-g[q[qh]]-C)*(g[i]-g[q[qh]]-C);
x[i]=g[i];
y[i]=f[i]+(g[i]+C)*(g[i]+C);
for (;qh<qt&&Slope(q[qt-1],i)<Slope(q[qt-1],q[qt]);q[qt--]=0);
q[++qt]=i;
}
printf("%lld\n",f[n]);
return 0;
}