题意:P 教授有编号为
- 在一个一维容器中的玩具编号是连续的。
- 同时如果一个一维容器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物。形式地说,如果将第
件玩具到第 个玩具放到一个容器中,那么容器的长度将为 。
制作容器的费用与容器的长度有关,根据教授研究,如果容器长度为
数据结构与约定:对于所有数据,满足
解析:建议在学习斜率优化之前先了解单调队列优化 DP。
我们可以知道,对于这种
但是如果形如
来看看这道题,我们设
表示将第
我们把包含
拆开得到:
移项得到:
我们令
接下来是一个无比重要的性质:
如果
且 ,那么 比 更优,否则 比 更优。即斜率的单调性。
证明:
我们假设
展开再移项得:
即:
故:
假设成立,得证。
假设在这个平面坐标系上存在点
接下来也是一个非常重要的性质:
坐标系上,每次决策时可能选取的最优的点组成了一个下凸包,即相邻两点斜率单调递增。
证明:
依然采用假设法,同时采用反证法。
假设有三个点

那么
- 当
时,由第一个性质可知, 比 优, 比 优, 不是最优; - 当
时,同理, 比 优, 比 优, 不是最优; - 当
时,同理, 比 优, 比 优, 不是最优。
即无论如何
所以我们需要维护一个下凸包,即

即下凸包的斜率永远单调递增,可以用单调队列来维护这个凸包,由两个性质可得,最优点就是下凸包中第一个斜率大于
我们维护每个可能的最优点,首先第一步,取出最优的点,即每次在队头判断是否
第二步按照转移方程更新
第三步就是维护斜率的单调递增,判断
第四步将
最终
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<ctime>
#define INF 1e9
using namespace std;
const int maxn=50010;
int n,l;
int head,tail,q[maxn];
double sum[maxn],f[maxn];
double a(int i)
{
return sum[i]+i;
}
double b(int i)
{
return a(i)+l+1;
}
double x(int i)
{
return b(i);
}
double y(int i)
{
return f[i]+b(i)*b(i);
}
double slope(int i,int j)
{
return (y(i)-y(j))/(x(i)-x(j));
}
int main()
{
scanf("%d%d",&n,&l);
for(int i=1;i<=n;i++)
{
scanf("%lf",&sum[i]);
sum[i]+=sum[i-1];
}
head=1;
tail=1;
for(int i=1;i<=n;i++)
{
while(head<tail&&slope(q[head],q[head+1])<2*a(i))//保持单调最优性
head++;
f[i]=f[q[head]]+(a(i)-b(q[head]))*(a(i)-b(q[head]));
while(head<tail&&slope(i,q[tail])<slope(q[tail-1],q[tail]))//维持斜率单调递增,下凸包
tail--;
q[++tail]=i;
}
printf("%lld",(long long)f[n]);
return 0;
}

