P3628 [APIO2010] 特别行动队 题解
题目传送门
蒟蒻的第一篇斜率优化题解。
思路
首先定义状态
根据定义很容易推出
其中
去括号,得
容易发现
为了使原式转换成
然后就转换完成了,而且有了新的状态转移方程:
单调队列维护凸壳即可。
斜率优化dp总结
第一步,推出
第二步,去括号、移项,找到唯一的变量
第三步,
第四步,单调队列(特殊情况用其它数据结构,如平衡树)维护凸壳。
最后输出答案。
Code
#include <iostream>
using namespace std;
const int N = 1000005;
typedef long long LL;
LL f[N], s[N];
int q[N], a, b, c;
inline LL k(int i)
{
return 2 * a * s[i];
}
inline LL x(int i)
{
return s[i];
}
inline LL y(int i)
{
return f[i] + a * s[i] * s[i] - b * s[i];
}
double get(int i,int j)
{
return (double)(y(i) - y(j)) / (x(i) - x(j));
}
int main()
{
int n;
scanf("%d%d%d%d", &n, &a, &b, &c);
for (int i=1;i<=n;i++)
{
scanf("%d", &s[i]);
s[i] += s[i - 1];
}
int hh = 0, tt = 0;
for (int i=1;i<=n;i++)
{
while (hh < tt && get(q[hh], q[hh + 1]) > k(i))
hh ++;
f[i] = -k(i) * x(q[hh]) + y(q[hh]) + a * s[i] * s[i] + b * s[i] + c;
while (hh < tt && get(q[tt - 1], q[tt]) <= get(q[tt], i))
tt --;
q[++tt] = i;
}
printf("%lld", f[n]);
return 0;
}