题目
解析
很容易想到的 (dp):
设 (f_i) 表示已经处理完 (1..i) 并且 (i) 是直接复制的需要的最小花费
那么 (f_i=f_j+(i-j) imes (i-j-1)+c_i)
这就是经典的斜率优化 (dp),一般我们考虑两个决策谁会更优
考虑 (j,k) 两个决策,那么我们可以列个不等式,把它化成只关于 (j) 的式子和只关于 (k) 的式子放一边,剩下的放一边
再写成斜率的形式,具体分析怎么维护
式子如下:
[frac{2f_j+j^2+j-2f_k-k^2-k}{2j-2k} < i
]
小于号维护下凸壳,斜率和横坐标都单调增,可以用单调队列维护
(Code)
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long LL;
const int N = 1e6 + 5;
const LL INF = 1e15;
int n;
LL f[N] , c[N] , q[N];
inline double slope(int x , int y)
{
return (2.0 * f[y] + 1.0 * y * y + y - (2.0 * f[x] + 1.0 * x * x + x)) / (2.0 * y - 2.0 * x);
}
int main()
{
scanf("%d" , &n);
for(register int i = 1; i <= n; i++) scanf("%lld" , c + i);
int h = 1 , t = 1;
q[h] = 0;
for(register int i = 1; i <= n; i++)
{
while (h < t && slope(q[h] , q[h + 1]) < i) h++;
f[i] = f[q[h]] + (LL)(i - q[h]) * (i - q[h] - 1) / 2 + c[i];
while (t > h && slope(q[t - 1] , q[t]) > slope(q[t] , i)) t--;
q[++t] = i;
}
printf("%lld
" , f[n]);
}