首页 > 其他分享 >【学习笔记】斜率优化DP

【学习笔记】斜率优化DP

时间:2024-01-19 09:38:17浏览次数:27  
标签:int tt mid 笔记 times 斜率 DP dp

例题1.ACwing 301

为了方便,我们记 \(c_i\) 为c的前缀和,\(t_i\) 同理。

容易推出 \(O(n ^ 2)\) 方程:

\(dp_{i} = \min_{j=0}^{i-1}{(dp_j+s\times (c_n-c_j)+t_i\times (c_i-c_j))}\)

但是本题的数据范围是 3e5,所以考虑优化。

我们先把min给拆掉:

\(dp_i=dp_j+s\times c_n-s\times c_j=t_i\times c_i-t_i\times c_j\)

然后将其转为一个一次函数的形式:

\(dp_j=(s+t_i)c_j+dp_i-s\times c_n-c_i\times t_i\)

我们发现此时可以通过数学方法求出 \(dp_i\),但是我们要求最小。

此时不妨把每个 \((dp_j,c_j)\) 放在平面直角坐标系上。

图上黑点即上文所提到的点对,红色线则是此时斜率的代表。

我们要找到一个j,使得 \(dp_i\) 最小,即在图中将红线不断网上平移碰到第一个碰到的点。考虑挖掘这些点的性质,容易发现他们实际上就是一个下凸包,考虑维护下凸包,此时还有一个性质,记 \(k_i\) 表示 在凸包上相邻两点的连线的斜率,那么最优决策点就是第一个大于红线斜率的 \(k_i\) 的右端点。这时我们已经可以用二分去获取答案了,但是注意到本题还有一个性质就是对于单调递增的 \(i\) ,他的斜率也是单调递增的,而且每一次新加的点的横坐标也是单调递增的,那么我们可以直接用维护凸包的队列来获取答案。

查询:因为斜率单调递增,所以如果队头的斜率比现在的斜率小,那么把队头扔掉。

添加:因为横坐标单调递增,所以每一个新算出来的i都要加到下凸包里,但是如果队尾两点的斜率比该点到队尾连线的斜率大的话队尾就要扔掉。

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 3e5 + 5;
int n , s , t[N] , c[N] , dp[N] , q[N] , hh = 1 , tt = 1;
signed main()
{
	cin >> n >> s;
	for(int i = 1;i <= n;i ++)
	{
		cin >> t[i] >> c[i];
		t[i] = t[i - 1] + t[i];
		c[i] = c[i - 1] + c[i];
	}
	for(int i = 1;i <= n;i ++)
	{
		while(hh < tt && dp[q[hh + 1]] - dp[q[hh]] <= (t[i] + s) * (c[q[hh + 1]] - c[q[hh]]))hh ++;
		int j = q[hh];
		dp[i] = dp[j] - (s + t[i]) * c[j] + s * c[n] + c[i] * t[i];
		while(hh < tt && (dp[q[tt]] - dp[q[tt - 1]]) * (c[i] - c[q[tt]]) >= (dp[i] - dp[q[tt]]) * (c[q[tt]] - c[q[tt - 1]]))tt --;
		q[++ tt] = i;
	}
	cout << dp[n] << '\n';
	return 0;
}

接下来,我们考虑加强版怎么去做。即P5782。

注意到区别就是此时 \(t_i\) 是可以取到负数的。那么这就意味着斜率不在是单调递增的了,但是由于 \(c_i\) 是单调递增的,所以我们每次只能去二分获取答案。

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 3e5 + 5;
int n , s , hh = 1 , tt = 1 , q[N] , t[N] , c[N] , dp[N];
bool check(int mid , int i)
{
	return (dp[q[mid + 1]] - dp[q[mid]]) > (s + t[i]) * (c[q[mid + 1]] - c[q[mid]]);
}
int search(int i)
{
	int l = hh , r = tt , ans;
	while(l < r)
	{
		int mid = l + r >> 1;
		if(check(mid , i))ans = mid , r = mid;
		else l = mid + 1;
	}
	return q[r];
}
signed main()
{
	cin >> n >> s;
	for(int i = 1;i <= n;i ++)cin >> t[i] >> c[i];
	for(int i = 1;i <= n;i ++)t[i] = t[i - 1] + t[i] , c[i] = c[i - 1] + c[i];
	for(int i = 1;i <= n;i ++)
	{
		int j = search(i);
		dp[i] = dp[j] - (s + t[i]) * c[j] + s * c[n] + c[i] * t[i];
		while(hh < tt && (dp[q[tt]] - dp[q[tt - 1]]) * (c[i] - c[q[tt]]) >= (dp[i] - dp[q[tt]]) * (c[q[tt]] - c[q[tt - 1]])) tt --;
		q[++ tt] = i;
	}
	cout << dp[n] << '\n';
	return 0;
}

标签:int,tt,mid,笔记,times,斜率,DP,dp
From: https://www.cnblogs.com/zjc2008/p/17973904

相关文章

  • 笔记重修计划三:线性基(施工中)
    正在备战THUWC,暂时停更。目前准备将这一系列内容迁移到cnblogs。本文属于笔记重修计划中的第三部,主要介绍广义的线性基与高斯消元的关联吗,以及在OI中应用较广的异或线性基。建议先阅读重修计划二高斯消元(目前很需要施工故未公开)的内容。其实我觉得这两章的内容如果分开来看......
  • 笔记重修计划一:斜率优化 dp & cdq 分治维护凸包(施工中)
    施工中,但是目前暂停施工。前言刷cdq分治的时候做到了这题,发现自己不是很懂这个东西,跑回去看自己几个月前写的斜率优化dp笔记,当时认为自己弄得很明白了,但现在看来简直就是皮毛,遂弄明白后写下此文,希望自己之后有更多启发时能继续充实这篇文章。若有不妥之处望指出。如果单调......
  • 大三寒假学习进度笔记9
    今日学习时间一小时,学习内容:通过不同格式构建DataFrame对象,包括基于Pandas的DF转换,读取text,csv,json和jparquet创建。jparquet具有以下特点:列式存储自带Schema具备PredicateFilter特性一个Parquet文件的内容由Header、DataBlock和Footer三部分组成。在文件的首尾各有一个......
  • 2024/1/18学习进度笔记
    今天研究了外包杯的题目。我们做的主要是一个虚拟数字人的项目,这里记录下在windows上配置pytorch3d以及freqencoder,gridencoder,raymarchingshencoder这几个库的过程首先这几个库是用过setup.py进行安装的,也就是pythonsetup.pyinstall安装前电脑里必须要装好了VisualStu......
  • 《拓扑学》复习笔记
    是1.15写的,但仅存了草稿,1.18终于想起来发布,没想到发布时间变成今天了(?麻,一点不懂,记录一下习题课感觉对于数学课,敲公式对学的效果比较有限,还是回去手写一遍其实写了,但截图发博客很麻烦。考前复习到凌晨三点,把讲义全看完了,但看过≠我会。此外还和好同学们讨论了往年......
  • stm32笔记[12]-LoRa通信
    摘要在蓝桥杯物联网的CT127C开发板上测试LoRa通信;Node_A按下按钮触发按键中断,经过定时器消抖后触发LoRa发送函数并切换LED的状态,Node_B接收到数据后在屏幕显示累计次数.开发环境Keil5.35.00HAL库版本:STM32CubeFW_L0V1.12.0STM32CubeMX:6.2.1原理简介LoRa简介[htt......
  • 学习笔记7
    DataFrame的创建Spark2.0版本开始,Spark使用全新的SparkSession接口替代Spark1.6中的SQLContext及HiveContext接口来实现其对数据加载、转换、处理等功能。SparkSession实现了SQLContext及HiveContext所有功能;SparkSession支持从不同的数据源加载数据,并把数据转换成DataFrame,支持......
  • Merge sort【1月18日学习笔记】
    点击查看代码//Mergesort#include<iostream>usingnamespacestd;voidmerge(intL[],intR[],intA[],intnL,intnR){//将两个已排序数组合并填入 inti=0,j=0,k=0;//i,j为未拾取元素索引,k为归并数组索引 while(i<nL&&j<nR){ if(L[i]<R[j]){......
  • 2024.1.18-每日进度笔记
    今天,我主要尝试了通过摄像头拍照并保存在本地指定文件。 参考:百度文心一言的回复。 <%@pagelanguage="java"contentType="text/html;charset=UTF-8"pageEncoding="UTF-8"%><!DOCTYPEhtml><html><head><title>获取摄像头画面并拍照</title......
  • 「笔记」哈希
    目录写在前面哈希是什么?写在最后写在前面大部分内容来自高中时期讲课PPT,在这里整理成了适合自学的形式。哈希是什么?一种用于统计复杂信息的的不完美算法。构造一个满射[1]的哈希函数,将复杂信息映射到便于统计的信息上。丢失了部分信息。写在最后进度有点太赶了!题单太难......