• [HNOI2008]玩具装箱TOY


    洛谷题目链接

    动态规划$+$单调队列$+$斜率优化

    身为$dp$蒟蒻的我,准备学斜率优化和单调队列,自然不能放过这个经典题目了,我们对于这题很容易想出一个暴力式子:

    ($sum[i]$为前缀和)

    $f[i]=min(f[i],f[j]+(sum[i]-sum[j]+i-j-L-1)^2)$

    我们不考虑最小值,把$sum[i]+i$用$a[i]$代替,$sum[j]+j+L+1$用$b[j]$代替,那么式子整理一下如下:

    $f[i]=f[j]+(a[i]+b[j])^2$

    去括号:

    $f[i]=f[j]+a[i]^2+2a[i]b[j]+b[j]^2$

    移项:

    $f[j]+b[j]^2=2a[i]b[j]+f[i]+a[i]^2$

    设$y=f[j]+b[j]^2$,$x=b[j]$,$b=f[i]+a[i]^2$,这就很像一次函数了,那么斜率自然就是$k=2a[i]$了

    为什么这么设呢,因为我们发现$y,x,k$在知道$i,j$时可以快速求出

    $f[i]$的含义转化为:当上述直线过点$P(b[j],f[j]+b[j]^2)$时,直线在$y$轴的截距加上$a[i]^2$(一个定值)

    而题目即为找这个截距的最小值

    而且我们仔细一看发现会有单调性,于是用单调队列维护最小值。

    代码如下:

    // luogu-judger-enable-o2
    #include<iostream>
    #include<cstdio>
    #define N 50007
    #define int long long
    using namespace std;
    int n,L;
    int sum[N],que[N],f[N];
    int A(int i)
    {
    	return sum[i]+i;
    }
    int B(int i)
    {
    	return sum[i]+i+1+L;
    }
    int X(int i)
    {
    	return B(i);
    }
    int Y(int i)
    {
    	return f[i]+B(i)*B(i);
    }
    int Get_k(int i,int j)
    {
    	return (Y(i)-Y(j))/(X(i)-X(j));
    }
    signed main()
    {
    	scanf("%lld%lld",&n,&L);
    	for(int i=1;i<=n;++i)
    	{
    		scanf("%lld",&sum[i]);
    		sum[i]+=sum[i-1];
    	}
    	int head=1,tail=1;
    	for(int i=1;i<=n;++i)
    	{
    		while(head<tail&&Get_k(que[head],que[head+1])<2*A(i))
    			++head;
    		f[i]=f[que[head]]+(A(i)-B(que[head]))*(A(i)-B(que[head]));
    		while(head<tail&&Get_k(que[tail],que[tail-1])>Get_k(i,que[tail-1]))
    			--tail;
    		que[++tail]=i;
    	}
    	printf("%lld",f[n]);
    	return 0;
    }
    

      

  • 相关阅读:
    Python 42 mysql用户管理 、pymysql模块
    Python 41 多表查询 和 子查询
    Python 41 完整查询语句 和 一堆关键字
    Python 40 数据库-外键约束 、多对一与多对多的处理
    Python 40 数据库-约束
    Python 38 注册和修改密码
    eas之关于编码规则
    eas之界面之间传递参数
    eas之获取集合
    eas之单据删除代码
  • 原文地址:https://www.cnblogs.com/yexinqwq/p/10214547.html
Copyright © 2020-2023  润新知