[BZOJ1010][HNOI2008]玩具装箱toy(斜率优化dp)

题目描述

传送门

题解

题目描述认真读
转移方程: f(i)=min{f(j)+(ij1+sisjL)2}
刚开始上来就化然后发现不可做。
考虑换元 令 pi=si+i,L=L+1
f(i)=min{f(j)+(pipjL)2}
然后展开
f(i)=min{2pjpi+f(j)+p2j+2pjL}+p2i+L22piL
k=2pj,b=f(j)+p2j+2pjL
明显可以用斜率优化。

这道题启示我们:一定要把ij相关的放在一起!

代码

#include
#include
#include
using namespace std;
#define LL long long

const int max_n=5e4+5;

LL n,L,x;
LL s[max_n],p[max_n];
LL q[max_n],head,tail;
LL f[max_n];

inline LL K(LL j){return -2*p[j];}
inline LL B(LL j){return f[j]+p[j]*p[j]+2*L*p[j];}
inline LL Y(LL i,LL j){return K(j)*p[i]+B(j);}
inline bool cmp(LL x1,LL x2,LL x3){
    LL w1=(K(x1)-K(x3))*(B(x2)-B(x1));
    LL w2=(K(x1)-K(x2))*(B(x3)-B(x1));
    return w1>=w2;
}

int main(){
    scanf("%lld%lld",&n,&L);
    for (LL i=1;i<=n;++i) scanf("%lld",&x),s[i]=s[i-1]+x,p[i]=s[i]+i; L++;
    head=tail=0;
    for (LL i=1;i<=n;++i){
        while (headq[head])>=Y(i,q[head+1])) head++;
        f[i]=Y(i,q[head])+p[i]*p[i]-2*L*p[i]+L*L;
        while (headq[tail-1],q[tail])) tail--;
        q[++tail]=i;
    }
    printf("%lld\n",f[n]);
}

总结

强转注意中间爆int

你可能感兴趣的:(题解,dp,省选)