跟佣神(orz)请教了一番大概会了基础的斜率优化:
基础的斜率优化一般就是两种情况:(斜率式子)<i 且i单调增或者 (斜率式子)>i 且i单调减。
对于第一种情况,也就是斜率单调增的,维护队头很好理解,维护队尾的时候,因为我们要保证斜率递增,所以如果(q[r],q[r-1])的斜率大于(i,q[r]),那么我们就把r给踢掉。
第二种情况就直接反过来想就可以了。
对于这题:
f[i]表示在第i个点上放守卫塔,裸的方程为
我们设x>y且x优于y,那么把式子化简以后得到:
然后如上文说的那样直接斜率优化搞一搞。。。
读入没开lld被坑了一发。。。
#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
#define ll long long
const int N=1e6+5;
ll n,a[N],l,r,q[N];
ll f[N];
ll i,j;
ll getY(ll x,ll y){
return (2*f[x]+x*x+x)-(2*f[y]+y*y+y);
}
ll getX(ll x,ll y){
return 2*(x-y);
}
int main(){
scanf("%lld",&n);
for (i=1;i<=n;i++)
scanf("%lld",&a[i]);
l=r=q[0]=0;
for (i=1;i<=n;i++){
while (l<r && getY(q[l+1],q[l])<i*getX(q[l+1],q[l])) l++;
j=q[l];
f[i]=f[j]+a[i]+(i-j)*(i-j-1)/2;
while (l<r && getY(q[r],q[r-1]) * getX(i,q[r]) > getY(i,q[r]) * getX(q[r],q[r-1])) r--;
q[++r]=i;
}
printf("%lld\n",f[n]);
return 0;
}