题面:Luogu3195 BZOJ1010
本来以为斜率优化是个什么高级东西。。。这题入门之后……
发现也没什么难的吧
O(n2) 做法:
f[i] 表示选完1~i个物品所花最小花费
转移: f[i]=min(f[j]+(i−j−1+s[i]−s[j]−L)2)
s[i] 表示从1~i的 c[i] 之和
O(n) 做法:
我们考虑怎么把上面的 O(n) 的转移时间优化到 O(1)
显然,如果 f[i] 从j转移过来比从k转移过来优的话,要满足
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define int long long
using namespace std;
int n,L,a[1000001],q[1000001],s[1000001],f[1000001]={0};
inline int sqr(int x){return x*x;}
inline double check(int x,int y){
return (double)((f[x]+sqr(s[x]+L)-f[y]-sqr(s[y]+L))/(2.0*(s[x]-s[y])));
}
signed main()
{
scanf("%lld%lld",&n,&L);L++;
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
a[i]+=a[i-1];s[i]=a[i]+i;
}
int l=1,r=1;q[1]=0;
for(int i=1;i<=n;i++){
while(lq[l+1],q[l])<s[i]+1.0)l++;
f[i]=f[q[l]]+sqr(s[i]-s[q[l]]-L);
while(lq[r],q[r-1])>check(i,q[r]))r--;
q[++r]=i;
}
printf("%lld",f[n]);
return 0;
}