• [HNOI2008]玩具装箱TOY


    题面在这里

    题意

    P教授有(n)个玩具,第(i)个玩具的长度为(c_i)
    把这(n)个玩具分成若干段,
    每一段的长度为(x=(r-l+sum_{k=l}^{r}{c_k})^2),代价为((x-L)^2)
    求把(n)个玩具分成若干段的最小代价

    数据范围

    [1le Nle50000,1le L,c_ile10^7 ]

    sol

    (sum[i]=sum_{k=1}^{i}c[k])
    我们很快就可以想到一个朴素的DP:设(f[i])为只考虑前(i)个玩具的最小代价,有

    [f[i]=min_{j=0}^{i-1}{[f[j]+(i-j-1+s[i]-s[j]-L)^2]} ]

    (1D/1D),复杂度为(O(n^2))

    斜率优化(单调队列)

    (sum[k]=s[k]+k)(l=L+1),有

    [f[i]=min_{j=0}^{i-1}{[f[j]+(sum[i]-sum[j]-l)^2]} ]

    [=min_{j=0}^{i-1}{[f[j]+(sum[i]-l)^2+sum[j]^2-2 sum[j](sum[i]-l)]} ]

    [=min_{j=0}^{i-1}{[f[j]+sum[j]^2-2 sum[j](sum[i]-l)]}+(sum[i]-l)^2 ]

    外面的部分忽略,
    (f[j]+sum[j]^2=y_j)(sum[j]=x_j)(2(sum[i]-l)=k_i)
    于是我们有(f[i]-(sum[i]-l)^2=min(y_j-k_ix_j))

    由于直线方程(y=kx+b)于是(b=y-kx)
    (k)单调递增的情况下,我们最小化的目标是截距
    于是通过单调队列维护斜率递增的点集((x_i,y_i))

    询问:取出队头节点直到(kle frac{y_{l+1}-y_l}{x_{l+1}-x_l})
    也就是(k imes(x_{l+1}-x_l)le y_{l+1}-y_l)
    然后以队头结点作为答案
    插点:弹出队尾直到斜率递增((frac{y_{r-1}-y_r}{x_{r-1}-x_r}lefrac{y_r-qy}{x_r-qx})),
    也就是((y_{r-1}-y_r) imes(x_r-qx)le (y_r-qy) imes(x_{r-1}-x_r))

    代码

    #include<bits/stdc++.h>
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<iomanip>
    #include<cstring>
    #include<complex>
    #include<vector>
    #include<cstdio>
    #include<string>
    #include<bitset>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<map>
    #include<set>
    #define mp make_pair
    #define pb push_back
    #define RG register
    #define il inline
    using namespace std;
    typedef unsigned long long ull;
    typedef vector<int>VI;
    typedef long long ll;
    typedef double dd;
    const dd eps=1e-10;
    const int mod=1e8;
    const int N=50010;
    il ll read(){
    	RG ll data=0,w=1;RG char ch=getchar();
    	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    	if(ch=='-')w=-1,ch=getchar();
    	while(ch<='9'&&ch>='0')data=data*10+ch-48,ch=getchar();
    	return data*w;
    }
    
    il void file(){
    	freopen(".in","r",stdin);
    	freopen(".out","w",stdout);
    }
    
    ll n,l,c[N],s[N],sum[N],f[N];
    struct node{ll x,y;};node Q[N];ll L=1,R;
    il void insert(node q){
    	while(L<R&&(Q[R-1].y-Q[R].y)*(Q[R].x-q.x)>(Q[R].y-q.y)*(Q[R-1].x-Q[R].x))R--;
    	Q[++R]=q;
    }
    il ll query(ll k){
    	while(L<R&&k*(Q[L+1].x-Q[L].x)>Q[L+1].y-Q[L].y)L++;
    	return Q[L].y-k*Q[L].x;
    }
    
    int main()
    {
    	n=read();l=read()+1;
    	for(RG int i=1;i<=n;i++)
    		c[i]=read(),s[i]=s[i-1]+c[i],sum[i]=s[i]+i;
    	
    	insert((node){0,0});
    	for(RG int i=1;i<=n;i++){
    		f[i]=query(2*(sum[i]-l))+(sum[i]-l)*(sum[i]-l);
    		insert((node){sum[i],f[i]+sum[i]*sum[i]});
    	}
    	
    	printf("%lld
    ",f[n]);
    	
    	return 0;
    }
    
  • 相关阅读:
    add custom attribute to standard windows controls
    产生0到1之间均匀分布的一个随机数与随机数序列
    (HDOJ 1002)A + B Problem II
    递推问题系列1幂积序列
    杭电题目分类解答
    (HDOJ 1003)Max Sum
    快排序(递归算法)
    (HDOJ 1004)Let the Balloon Rise
    (HDOJ 1005)Number Sequence
    一个关于去除数组重复元素的问题(C语言实现)
  • 原文地址:https://www.cnblogs.com/cjfdf/p/8630525.html
Copyright © 2020-2023  润新知