【BZOJ3156】防御准备,斜率优化DP

传送门
写在前面:感觉文化课要跪
思路:老样子,先化转移式
设f[i]为在第i个位置建守卫塔时的最小费用,那么转移方程就是
f[i]=min(f[j]+(ij)(ij1)/2)+a[i])
i和j之间放木偶的总费用就是(i-j)*(i-j-1)/2
设x>y且x转移比y优
化简得
2(f[x]f[y]+x(x+1)y(y+1))(xy)<2i
注意:思考初始转移方程时要小心,仔细琢磨转移是否正确,如果一开始就错了,后面就都错了,这还是要慢慢通过做题提升
代码:

#include<bits/stdc++.h>
#define LL long long
#define M 1000002
using namespace std;
int n,head=1,tail=1;
int a[M],q[M];
LL f[M];
int in()
{
    int t=0;char ch=getchar();
    while (ch>'9'||ch<'0')ch=getchar();
    while (ch>='0'&&ch<='9') t=(t<<3)+(t<<1)+ch-'0',ch=getchar();
    return t;
}
double Get(int x,int y)
{
    return (double)(2*(f[x]-f[y])+(LL)x*(x+1)-(LL)y*(y+1))/(double)(x-y);
}
main()
{
    n=in();
    for (int i=1;i<=n;i++) a[i]=in();
    for (int i=1;i<=n;i++)
    {
        while (head<tail&&Get(q[head+1],q[head])<(i<<1)) head++;
        f[i]=f[q[head]]+a[i]+(i-q[head])*(i-q[head]-1)/2;
        while (head<tail&&Get(i,q[tail])<Get(q[tail],q[tail-1])) tail--;
        q[++tail]=i;
    }
    printf("%lld",f[n]);
}

你可能感兴趣的:(【BZOJ3156】防御准备,斜率优化DP)