zoukankan      html  css  js  c++  java
  • P3195 [HNOI2008]玩具装箱TOY

    题目

    纪念不看题解(A)掉的第一个斜率优化dp:P3195 [HNOI2008]玩具装箱TOY

    一个月后补的重点:斜率优化的本质就是利用推出来的公式决定维护一个凸包,用单调队列来维护这个凸包,因为我们假定(j<k,dp_j>dp_k),所以每次决策显然就取队头,从而得到最优解

    做法

    定义数组(sum_i)为长度前缀和,数组(dp_i)为前(i)个玩具的最小花费

    当前块末(i)与前一块末(j)状态转移为(dp_i=dp_{j-1}+i-(j+1)+sum_i-sum_j-L)

    假设(j<k),从(k)转移比(j)转移更优:

    (dp_j+[i-(j+1)+sum_i-sum_j-L]^2>)

    (dp_k+[i-(k+1)+sum_i-sum_k-L]^2)

    (Longrightarrow)

    (dp_j+[(i+sum_i-L)+(-j-1-sum_j)]^2>)

    (dp_k+[(i+sum_i-L)+(-k-1-sum_k)]^2)

    (Longrightarrow)

    (dp_j+(i+sum_i-L)^2+2(i+sum_i-L)(-j-1-sum_j)+(-j-1-sum_j)^2>)

    (dp_k+(i+sum_i-L)^2+2(i+sum_i-L)(-k-1-sum_k)+(-k-1-sum_k)^2)

    (Longrightarrow)

    (dp_j+2(i+sum_i-L)(-j-1-sum_j)+(-j-1-sum_j)^2>)

    (dp_k+2(i+sum_i-L)(-k-1-sum_k)+(-k-1-sum_k)^2)

    (Longrightarrow)

    (dp_j-dp_k+(-j-1-sum_j)^2-(-k-1-sum_k)^2>)

    ((i+sum_i-L) {2[(-k-1-sum_k)-(-j-1-sum_j)]})

    (Longrightarrow)

    (dfrac{dp_j-dp_k+(-j-1-sum_j)^2-(-k-1-sum_k)^2}{2[(-k-1-sum_k)-(-j-1-sum_j)]}>i+sum_i-L)

    :然后你就会样例都过不了,为什么?根据单调性(2[(-k-1-sum_k)-(-j-1-sum_j)])为负,符号要变,所以最后的式子为

    (dfrac{dp_j-dp_k+(-j-1-sum_j)^2-(-k-1-sum_k)^2}{2[(-k-1-sum_k)-(-j-1-sum_j)]}<i+sum_i-L)

    (i+sum_i-L)单调递增,所以我们用单调队列维护上凸包

    My complete code

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const LL maxn=200000;
    inline LL Read(){
    	LL x=0,f=1; char c=getchar();
    	while(c<'0'||c>'9'){
    		if(c=='-') f=-1; c=getchar();
    	}
    	while(c>='0'&&c<='9')
    	    x=(x<<3)+(x<<1)+c-'0',c=getchar();
    	return x*f;
    }
    LL n,L,head,tail;
    LL sum[maxn],dp[maxn],q[maxn];
    inline double Get(LL i){
    	return (double)i+sum[i]-L;
    }
    inline LL P_(LL x){
    	return x*x;
    }
    inline double Xl(LL j,LL k){
    	return (double)
    	(dp[j]-dp[k]+P_(-j-1-sum[j])-P_(-k-1-sum[k]))/(2*(-k-1-sum[k]+j+1+sum[j]));
    }
    int main(){
    	n=Read(),L=Read();
    	for(LL i=1;i<=n;++i)
    		sum[i]=sum[i-1]+Read();
    	dp[1]=P_(sum[1]-L),
    	q[head=tail=1]=1;
    	for(LL i=2;i<=n;++i){
    		while(head<tail&&Xl(q[head],q[head+1])<Get(i))
    		    ++head;
    		LL j=q[head];
    		LL val=i-(j+1)+sum[i]-sum[j]-L;
    		dp[i]=min(dp[j]+P_(val),P_(i-1+sum[i]-L));
    		while(head<tail&&Xl(q[tail-1],q[tail])>Xl(q[tail],i))
    		    --tail;
    		q[++tail]=i;
    	}
    	printf("%lld",dp[n]);
        return 0;
    }
    
  • 相关阅读:
    联考20200604 T2 宝石
    联考20200604 T1 旅游
    联考20200603 T2 排列
    [HAOI2017]八纵八横
    联考20200603 T1 解码
    [POI2011]KON-Conspiracy
    CF917D Stranger Trees
    CF1278F Cards
    CF809E Surprise me!
    NOI2016 循环之美
  • 原文地址:https://www.cnblogs.com/y2823774827y/p/10176159.html
Copyright © 2011-2022 走看看