思路:
设
f[i]
表示
1
到
状态转移方程:
f[i]=min{f[j]+(s[i]−s[j]+i−j−1−L)2}
考虑对方程进行优化。
令
t[i]=s[i]+i
,则
f[i]=min{f[j]+(t[i]−t[j]−1−L)2}
由于
c[i]
非负,所以
s[i]
在
i
增长时单调不减。
令
设
i
从
若方案
q
优于
展开:
f[p]−2m×t[p]+t[p]2>f[q]−2m×t[q]+t[q]2
整理:
(f[q]+t[q]2)−(f[p]+t[p]2)2×(t[q]−t[p])<m
因为 i 增加的的时候,
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const int maxn = 50010;
int n, L;
ll c[maxn], f[maxn], s[maxn], q[maxn], t[maxn], l, r;
ll sqr(ll x){return x*x;}
double slope(ll p, ll q){
return ((f[q]+sqr(t[q]))-(f[p]+sqr(t[p])))/(2.0*(t[q]-t[p]));
}
int main(){
scanf("%d%d", &n, &L);
for(int i = 1; i <= n; i ++){
scanf("%lld", &c[i]);
s[i] += s[i-1]+c[i];
t[i] = s[i] + i;
}
l = 1, r = 1;
for(int i = 1; i <= n; i ++){
while(l<r && slope(q[l], q[l+1]) < t[i]-L-1) l ++;
f[i] = f[q[l]] + sqr(t[i]-t[q[l]]-L-1);
while(l<r && slope(q[r-1], q[r]) > slope(q[r], i)) r --;
q[++ r] = i;
}
printf("%lld", f[n]);
return 0;
}