Description
Input
第一行为一个整数N表示战线的总长度。
第二行N个整数,第i个整数表示在位置i放置守卫塔的花费Ai。
Output
共一个整数,表示最小的战线花费值。
Sample Input
10
2 3 1 5 4 5 6 3 1 2
Sample Output
18
分析:
斜率优化dp
方程:
f[i]=min{f[j]+(j+1~i-1每一个木偶到i的距离)}
括号里的贡献:
dis表示每个节点到1号店的距离
f[i]=min{f[j]+(i-j-1) * (i-1) - (i-j-1) * (j+i-2)/2+a[i]}
画柿子:
tip
千万不要画错柿子!!!
我在这里稍微总结一下可以使用斜率优化的一般条件:
- 可以dp(其实就是具备最优子结构)
- 一般是在序列上,一维二维都可以
- 一般符合形式f[i]=f[j]+(i~j的贡献)
- 可以画出柿子来,具备斜率的形式
这里写代码片
#include<cstdio>
#include<cstring>
#include<cstring>
#define ll long long
using namespace std;
const int N=1000010;
ll f[N],a[N];
int n,q[N],tou,wei;
double get(int j,int k)
{
double x1=(double)f[j]+j-(j-j*j)/2;
double x2=(double)f[k]+k-(k-k*k)/2;
return (double)(x1-x2)/(j-k);
}
void doit()
{
int i;
tou=wei=0;
for (i=1;i<=n;i++)
{
while (tou<wei&&get(q[tou+1],q[tou])<i) tou++;
f[i]=f[q[tou]]+(i-q[tou]-1)*(i-1)-((i-q[tou]-1)*(q[tou]+i-2))/2+a[i];
while (tou<wei&&get(i,q[wei])<get(q[wei],q[wei-1])) wei--;
q[++wei]=i;
}
printf("%lld",f[n]);
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
doit();
return 0;
}