題面:Luogu3195 BZOJ1010
本來以爲斜率優化是個什麼高級東西。。。這題入門之後……
發現也沒什麼難的吧
轉移:
我們考慮怎麼把上面的
顯然,如果
其中
我們把
化開來是:
同除以
然後發現這個不等式化成了一個斜率不等式
所以我們可以斜率優化這個dp,其實就是維護一個下凸殼
每次把斜率大於s[i]的最小答案來轉移,最後把不是下凸殼的節點刪掉
用單調隊列維護一下就好了
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <iostream>
#include <ctime>
#include <map>
#include <queue>
#include <cstdlib>
#include <string>
#include <climits>
#include <set>
#include <vector>
#define int long long
using namespace std;
int n,L,a[1000001],q[1000001],s[1000001],f[1000001]={0};
inline int sqr(int x){return x*x;}
inline double check(int x,int y){
return (double)((f[x]+sqr(s[x]+L)-f[y]-sqr(s[y]+L))/(2.0*(s[x]-s[y])));
}
signed main()
{
scanf("%lld%lld",&n,&L);L++;
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
a[i]+=a[i-1];s[i]=a[i]+i;
}
int l=1,r=1;q[1]=0;
for(int i=1;i<=n;i++){
while(l<r&&check(q[l+1],q[l])<s[i]+1.0)l++;
f[i]=f[q[l]]+sqr(s[i]-s[q[l]]-L);
while(l<r&&check(q[r],q[r-1])>check(i,q[r]))r--;
q[++r]=i;
}
printf("%lld",f[n]);
return 0;
}