热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

2019牛客暑期多校训练营(第十场)JWoodProcessing(斜率优化DP)

>传送门<题意$n$个宽度为$w_{i}$,高为$h_{i}$的木块,要求分成$k$组,对于每组内的所有木块,高度都变为组内最低木块的高度,宽度保持不变

>传送门<

题意


$n$个宽度为$w_{i}$,高为$h_{i}$ 的 木块,要求分成$k$组,对于每组内的所有木块,高度都变为组内最低木块的高度,宽度保持不变,求变化的最小面积。

分析


由于$dp$状态定义不同写法也不同,这里给出一种解法

高度比较高的木块为迁就高度比较低的(为了$dp$方程及其优化),所以先把木板按照高度从高到低排序

如果设$d[i][k]$ 为前$ i $个分成 $k $份可以保留的最大面积,那么答案就是 $tot−d[n][k]$($tot$ 为初始总面积)

考虑如何转移

               $d[i][k]=max(d[j][k-1]+(pre[i]-pre[j])\cdot h[i])$

其中$pre$为宽度前缀和,即$pre[i]=\sum_{1}^{i}w[i] $。

暴力转移复杂度较高($O(n^{2})$),考虑如何优化。(这不就是个斜率优化嘛)

我们设$j_{1}

                $d[j_{1}][k−1]+(pre[i]−pre[j_{1}])\cdot h[i]

这时$j_{1}$可以从决策集中被删去,因为后者的$j_{2}$要比$j_{1}$更优。

上式可以化简为

              $\frac{d[j_{2}][k-1]-d[j_{1}][k-1]}{pre[j_{2}]-pre[j_{1}]}$>$h[i]$

这时我们维护一个单调递减的决策集就可以了

Code

#include 
#define empty (head>=tail)
#define ll long long
using namespace std;
const int maxn = 5e3+10, maxk = 2e3+10;
int n, k, head, tail, j;
ll pre[maxn], d[maxn][maxk], q[maxn];
struct node{int w ,h;}a[maxn];
bool cmp(node a, node b){return a.h > b.h;}
long double slope(int x, int y, int p) {
    return (long double)(d[y][p-1]-d[x][p-1])/(pre[y]-pre[x]);
}
int main()
{
    scanf("%d%d", &n, &k);
    ll sum = 0;
    for (int i = 1; i<= n; i++) {
        scanf("%d%d", &a[i].w, &a[i].h);
        sum += a[i].h * a[i].w;
    }
    sort(a+1, a+1+n, cmp);
    for (int i = 1; i <= n; i++) pre[i] = pre[i-1] + a[i].w;
    for(int p = 1; p <= k; p++) {
        head = tail = 1;
        for (int i = 1; i <= n; i++) {
            while(!empty&&slope(q[head],q[head+1],p)>a[i].h) head++;
            j = q[head]; d[i][p] = d[j][p-1]+a[i].h*(pre[i]-pre[j]);
            while(!empty&&slope(q[tail],q[tail-1],p);
            q[++tail] = i;
        }
    }
    printf("%lld\n", sum-d[n][k]);
    return 0;
}
View Code

 

思考


开始对木板高度排序那里,能想到的应该就直接想到了,没想到的应该是写转移方程的时候发现,排序后比较好写出转移方程,并且需要对其进行优化就会去关心排序的方向。原博主的博客一直都写的挺好的,但是我觉得这种东西还是要多看看各种博客,这会给你广阔的思路和一些对比。他有关斜率优化$dp$的题目里,写的都是由于$A[i]$是单调递增/递减,所以维护的是一个递增/递减的决策集,但是我在相关题目写的挺好的博客里看到的是,博主都是给出说明为什么维护一个凸包/凹包,而并没有说是因为上面的那种原因。另外这题,由于看过维护凸包的,类比的思想维护凹包原理上都是差不多的,不过之后还是要去写凹包相关题目(立flag)。遇到有困惑的地方,重新翻回去看大米饼的博客还有其他人的博客,感觉慢慢会清晰一点,$go\ on$~

 


推荐阅读
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • C# 7.0 新特性:基于Tuple的“多”返回值方法
    本文介绍了C# 7.0中基于Tuple的“多”返回值方法的使用。通过对C# 6.0及更早版本的做法进行回顾,提出了问题:如何使一个方法可返回多个返回值。然后详细介绍了C# 7.0中使用Tuple的写法,并给出了示例代码。最后,总结了该新特性的优点。 ... [详细]
  • 本文介绍了P1651题目的描述和要求,以及计算能搭建的塔的最大高度的方法。通过动态规划和状压技术,将问题转化为求解差值的问题,并定义了相应的状态。最终得出了计算最大高度的解法。 ... [详细]
  • 3.223.28周学习总结中的贪心作业收获及困惑
    本文是对3.223.28周学习总结中的贪心作业进行总结,作者在解题过程中参考了他人的代码,但前提是要先理解题目并有解题思路。作者分享了自己在贪心作业中的收获,同时提到了一道让他困惑的题目,即input details部分引发的疑惑。 ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 本文讨论了如何使用IF函数从基于有限输入列表的有限输出列表中获取输出,并提出了是否有更快/更有效的执行代码的方法。作者希望了解是否有办法缩短代码,并从自我开发的角度来看是否有更好的方法。提供的代码可以按原样工作,但作者想知道是否有更好的方法来执行这样的任务。 ... [详细]
  • Go语言实现堆排序的详细教程
    本文主要介绍了Go语言实现堆排序的详细教程,包括大根堆的定义和完全二叉树的概念。通过图解和算法描述,详细介绍了堆排序的实现过程。堆排序是一种效率很高的排序算法,时间复杂度为O(nlgn)。阅读本文大约需要15分钟。 ... [详细]
  • 本文讨论了一个数列求和问题,该数列按照一定规律生成。通过观察数列的规律,我们可以得出求解该问题的算法。具体算法为计算前n项i*f[i]的和,其中f[i]表示数列中有i个数字。根据参考的思路,我们可以将算法的时间复杂度控制在O(n),即计算到5e5即可满足1e9的要求。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • This article discusses the efficiency of using char str[] and char *str and whether there is any reason to prefer one over the other. It explains the difference between the two and provides an example to illustrate their usage. ... [详细]
author-avatar
睡姿决定发型
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有