这个题为什么有个*???
关于斜率优化又有了新的感悟
对于次优解的排除:假设对于i来说l是次优解。即满足k(q[l],q[l+1])<=k(i)时,l+1比l更优
k(q[l],q[l+1])表示这两个点连成一条线的斜率,k(i)表示在i处那根线的斜率,这个很容易就可以证明
对于提前排除不可能的解:假设r是考虑排除的点,now是考虑放入的点,即满足k(q[r-1],q[r])>=k(q[r],now)时,应该提前排除r
这个证明也特别简单,就是不等式换算一下
为什么要这样呢?因为这样两个式子都要计算k,把它封装成一个函数,那么代码量相对于上一篇博客那种写法来说就会小很多,而且思路看起来更加清晰,如果写错了更好修改。
二更:前面的话纯属放屁,有的斜率优化的题如果用k判断的话会有精度损失(转double)然后导致不能ac。应该只用乘法不用除法,最好写个x(i)宏和y(i)宏,不要使用k。
#include <cstdio>
#include <iostream>
#include <iomanip>
#include <string>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <set>
#include <vector>
#include <map>
#include <algorithm>
#include <cmath>
#include <stack>
#define INF 0x3f3f3f3f
#define IMAX 2147483646
#define LINF 0x3f3f3f3f3f3f3f3f
#define ll long long
#define ull unsigned long long
#define uint unsigned int
using namespace::std;
const int maxn = 1111111;
ll n, a, b, c, q[maxn];
ll aa[maxn],sum[maxn], f[maxn];
#define k(x,y) ((double)(f[y] - f[x] + a * sum[y] * sum[y] - a * sum[x] * sum[x] - b * sum[y] + b * sum[x]) / (a * (sum[y] - sum[x]) * 2))
int main() {
scanf("%lld%lld%lld%lld", &n, &a, &b, &c);
for (int i = 1; i <= n; i++)
scanf("%lld", aa + i), sum[i] = aa[i] + sum[i - 1];
int l = 1, r = 1;
for (int i = 1; i <= n; i++) {
while (l < r && k(q[l], q[l + 1]) <= sum[i]) ++l;
f[i] = f[q[l]] + a * (sum[i] - sum[q[l]]) * (sum[i] - sum[q[l]]) + b * (sum[i] - sum[q[l]]) + c;
while (l < r && k(q[r - 1], q[r]) >= k(q[r], i)) --r;
q[++r] = i;
}
printf("%lld\n", f[n]);
return 0;
}