luogu_P3195 [HNOI2008]玩具装箱TOY

时间:2019-10-08
本文章向大家介绍luogu_P3195 [HNOI2008]玩具装箱TOY,主要包括luogu_P3195 [HNOI2008]玩具装箱TOY使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

传送门:https://www.luogu.org/problem/P3195

显而易见:f[i]=min{ f[j]+( i-j-1+ sum[i]-sum[j]-m)^2 }  (f[i]表示前i件的最小花费)

化简  f[i]=f[j]+( (i+sum[i]) - (j+sum[j]+m+1) )^2

另 A(x)=x+sum[x]  B(x)=A(x)+m+1

上式化简 f[i]=f[j]+ A(i)^2 - 2*A(i)*B(j) + B(j)^2

    f[j] + B(j)^2 =f[i] + 2*A(i)*B(j) -A(i)^2

可见 是以 B(j) 为横坐标 f[j]+ B(j)^2 为纵坐标 2*A(i)为斜率

转移就很舒服了 YY一下就知道了!在队列转移时我用了 {l=1,r=0,l<=r}然后挂了,用的{l=r=0,l<r}就过了?

#include<cstdio>
#define R register
typedef long long ll;
using namespace std;
ll n,m,c[51000],sum[51000],q[51000],l=0,r=0,f[51000];
ll a(ll x){
    return sum[x]+x;
}
ll b(ll x){
    return a(x)+m+1;
}
ll Y(ll x){
    return f[x]+b(x)*b(x);
}
ll X(ll x){
    return b(x);
}
double slope(ll x,ll y){
    return (double)(Y(y)-Y(x))/(X(y)-X(x));
}
int main (){
    scanf("%lld%lld",&n,&m);
    for(R int i=1;i<=n;i++) scanf("%lld",&c[i]),sum[i]=sum[i-1]+c[i];
    for(R int i=1;i<=n;i++){
        while(l<r&&slope(q[l+1],q[l])<=a(i)<<1) l++;
        f[i]=(f[q[l]]+(a(i)-b(q[l]))*(a(i)-b(q[l])));
        while(l<r&&slope(i,q[r])<=slope(q[r],q[r-1])) r--;
        q[++r]=i;
    }
    printf("%lld",f[n]);
    return 0;
}
View Code

原文地址:https://www.cnblogs.com/coclhy/p/11634457.html