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

    [bzoj1010][HNOI2008]玩具装箱

    标签: DP 斜率优化


    题目链接

    题解

    (找草稿纸ing......)
    首先我们可以很容易写出dp的方程。

    [dp[i]=max(dp[j]+i-j+1+sum_{l=j+1}^ic[l]-L)^2)) ]

    [即dp[i]=max(dp[j]+(i-j-1+sum(i)-sum(j)-L)^2) ]

    [令f(i)=sum(i)+i,C=L+1 ]

    [则dp[i]=max(dp[j]+(f(i)-f(j)-C)^2) ]

    (现在假设i由j转移过来且j< k)

    [那么有dp[j]+(f(i)-f(j)-C)^2<=dp[k]+(f(i)-f(k)-C)^2 ]

    [化简得dp[j]-dp[k]+f(j)^2-f(k)^2<=2(f(j)-f(k))×(f(i)-C) ]

    [ecause j< k ,即 f(j)-f(k)< 0 ]

    [ herefore frac{dp[j]-dp[k]+f(j)^2-f(k)^2}{2(f(j)-f(k))}>=f(i)-C ]

    左边其实就是求斜率的公式,注意到值只与j,k有关,所以可以看成两个点。
    右边是递增的,这给我们动态弹点提供了条件。
    所以我们可以用单调队列来维护一个下凸壳。

    Code

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<set>
    #include<map>
    using namespace std;
    #define ll long long
    #define REP(i,a,b) for(int i=(a),_end_=(b);i<=_end_;i++)
    #define DREP(i,a,b) for(int i=(a),_end_=(b);i>=_end_;i--)
    #define EREP(i,a) for(int i=start[(a)];i;i=e[i].next)
    inline int read()
    {
    	int sum=0,p=1;char ch=getchar();
    	while(!(('0'<=ch && ch<='9') || ch=='-'))ch=getchar();
    	if(ch=='-')p=-1,ch=getchar();
    	while('0'<=ch && ch<='9')sum=sum*10+ch-48,ch=getchar();
    	return sum*p;
    }
    
    const int maxn=5e4+20;
    
    ll n,C;
    ll dp[maxn],s[maxn];
    
    void init()
    {
    	n=read();C=read()+1;
    	REP(i,1,n)s[i]=read()+1+s[i-1];
    }
    
    double count(int j,int k)
    {
    	return (double)(dp[j]+s[j]*s[j]-dp[k]-s[k]*s[k])/(2*(s[j]-s[k]));
    }
    
    int q[maxn],head,tail;
    
    
    void doing()
    {
    	head=1;q[++tail]=0;
    	REP(i,1,n)
    	{
    		while(head<tail && count(q[head],q[head+1])<s[i]-C)head++;
    		int x=q[head];
    		dp[i]=dp[x]+(s[i]-s[x]-C)*(s[i]-s[x]-C);
    		while(head<tail && count(q[tail-1],q[tail])>count(q[tail],i))tail--;
    		q[++tail]=i;
    	}
    	printf("%lld
    ",dp[n]);
    }
    
    int main()
    {
    	freopen("toy.in","r",stdin);
    	freopen("toy.out","w",stdout);
    	init();
    	doing();
    	return 0;
    }
    
    
    
  • 相关阅读:
    【luogu2756】 飞行员配对方案问题 [二分图匹配 匈牙利算法]
    [APIO2008]紧急集合
    2019.8.27 Za
    【luogu2763】试题库问题 [网络流 最大流]
    [CQOI2014]危桥 [网络流 最大流]
    【luogu1231】教辅的组成 [网络流 最大流]
    【网络流】
    【2019.8.24】
    【匈牙利算法】
    2019.8.23 Za [数论]
  • 原文地址:https://www.cnblogs.com/gzy-cjoier/p/7717760.html
Copyright © 2011-2022 走看看