Snowdrop修长廊
描述
Snowdrop现在是世界著名的工程师。因为重庆的天气太热了,
Snowdrop决定修一条长廊,并且长廊要覆盖必须覆盖的n个点。为
了简化整个问题,我们把一条路抽象成一维的,原点在0,有n个必须
覆盖的点,每个必须覆盖的点的坐标为,覆盖点的代价可以设成
(),其中,为固有花费。现在,
他想知道覆盖所有必须的点所需要的最小花费是多少。
输入
第一行输入一个T表示有T组样例
接下来块
每块第一行输入
接下来一行描述个点的距离原点位置
输出
输出最小花费
样例输入
1
10 5000
1
23
45
67
101
124
560
789
990
1019
样例输出
30726
【题意】中文题面。
【分析&解题思路】 裸斜率优化,就是要注意到dp[i]=dp[j-1]+(sum[i]-sum[j])^2里面,不包含j.dp[i]有初值,但是斜率优化不会考虑他自己是最优值的情况。
【AC代码】
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <stdio.h>
#include <iostream>
#include <algorithm>
typedef long long LL;
using namespace std;
const int maxn = 500010;
LL dp[maxn],sum[maxn],q[maxn];
LL n,m,head,tail;
LL get_DP(int j,int k)
{
return dp[k-1]+m+(sum[j]-sum[k])*(sum[j]-sum[k]);
}
LL get_UP(int j,int k) //yj-yk部分
{
return dp[j-1]+sum[j]*sum[j]-(dp[k-1]+sum[k]*sum[k]);
}
LL get_DOWN(int j,int k) //xj-xk部分
{
return 2*(sum[j]-sum[k]);
}
int main()
{
int tt;
scanf("%d",&tt);
while(tt--)
{
scanf("%I64d%I64d",&n,&m);
for(int i=1; i<=n; i++) scanf("%I64d",&sum[i]);
sum[0]=dp[0]=0;
head=tail=0;
q[tail++] = 0;
//斜率优化
for(int i=1; i<=n; i++)
{
//求解过程
dp[i]=dp[i-1]+m;
while(head+1<tail&&get_UP(q[head+1],q[head])<=sum[i]*get_DOWN(q[head+1],q[head])) head++;
dp[i] = min(get_DP(i,q[head]),dp[i]);
//维护解集
while(head+1<tail&&get_UP(i,q[tail-1])*get_DOWN(q[tail-1],q[tail-2])<=get_UP(q[tail-1],q[tail-2])*get_DOWN(i,q[tail-1]))
tail--;
q[tail++] = i;
}
printf("%lld\n",dp[n]);
}
return 0;
}