题目:https://www.luogu.org/problemnew/show/P3195
自己做斜率优化的第一道题。
推成斜率优化的样子很重要。
斜率优化的样子就是从 j 中求 i 的话,关系式里一个量只和 i 有关,一个量只和 j 有关,一个量同时和 i 与 j 有关。
这时可以把那个 同时和 i 与 j 有关的量 里的和 j 有关的量看成 x[ j ],把只和 j 有关的量看成 y[ j ],然后只和 i 有关的量就是截距、x[ j ]前面的就是式子里的斜率。
(为了推出这样的式子,可以设a,b等等,帮助自己推。大体思路是将与 i 或 j 或 i 和 j 有关的东西看成一个整体)
推出式子以后,找合适的 j 就是 j - 1 与 j 的斜率比式子里的斜率大(或小),而 j 与 j + 1 的斜率比式子里的斜率小(或大)的那个 j 。
找到 j 以后把式子变变形就得到推出dp[ i ] 的式子了。
可用单调队列。
把a什么的写成函数很方便。
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
#define db double
using namespace std;
const int N=;
int n,L,h=,t=,q[N];
ll s[N],dp[N];
db a(int i){return s[i]+i;}
db b(int i){return s[i]+i+L+;}
db x(int i){return b(i);}
db y(int i){return b(i)*b(i)+dp[i];}
db slope(int j,int i){return (y(i)-y(j))/(x(i)-x(j));}
int main()
{
scanf("%d%d",&n,&L);ll z;
for(int i=;i<=n;i++)
{
scanf("%lld",&z);s[i]=s[i-]+z;
}
for(int i=;i<=n;i++)
{
while(h<t&&slope(q[h],q[h+])<*a(i))h++;
dp[i]=(a(i)-b(q[h]))*(a(i)-b(q[h]))+dp[q[h]];
while(t>h&&slope(q[t-],q[t])>slope(q[t-],i))t--;
q[++t]=i;
}
printf("%lld",dp[n]);
return ;
}