「学习笔记」Garsia-Wachs 算法
前言
本文的资料和图片均来自 \(\texttt{OI-Wiki}\)。
引入
题目描述
在一个操场上摆放着一排 \(N\) 堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的 \(2\) 堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。
试设计一个算法,计算出将 \(N\) 堆石子合并成一堆的最小得分。
\((N \leq 40000)\)
过程
我们看到这个题,自然而然会想到区间 DP,即朴素的做法。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll r[600], g[600];
ll dp[600][600];
int main() {
int n;
scanf("%d", &n);
for (int i = 1; i <= n; ++ i) {
scanf("%lld", &r[i]);
r[i + n] = r[i];
g[i] = g[i - 1] + r[i];
dp[i][i] = 0;
}
for (int i = n + 1; i <= 2 * n; ++ i) {
dp[i][i] = 0;
g[i] = g[i - 1] + r[i];
}
for (int l = 1; l < n; ++ l) {
for (int i = 1, j = i + l; i < n * 2 && j <= n * 2; ++ i, j = i + l) {
dp[i][j] = 100000000;
for (int k = i; k < j; ++ k) {
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] + g[j] - g[i - 1]);
}
}
}
ll minn = 0x3f3f3f3f;
for (int i = 1; i <= n; ++ i) {
minn = min(minn, dp[i][i + n - 1]);
}
printf("%lld", minn);
return 0;
}
交上去后,你会发现,RE 了 \(7\) 个。
为什么?
因为 \(n\) 太大了,二维数组开不下,其次就算是用了什么不为人知的手段开下了这么大的数组,\(n^2\) 的复杂度也铁定超时。
这可怎么办呢?
下面介绍一种专门处理石子合并这类问题的算法——Garsia-Wachs 算法
Garsia-Wachs 算法
Garsia-Wachs 的步骤如下:
在序列的两端设置极大值。
在序列中找到前三个连续的权重值 \(x, y, z\) 使得 \(x \leq z\)。因为序列结尾的最大值大于之前的任意两个有限值,所以总是存在这样的三元组。
从序列中移除 \(x\) 和 \(y\),并在原来 \(x\) 的位置以前大于或等于 \(x+y\) 且距 \(x\) 最近的值的右边重新插入元素,元素值为 \(x+y\)。因为左端最大值的存在,所以总是存在这样的位置。
为了有效地实现这一阶段,该算法可以在任何平衡二叉查找树结构中维护当前值序列。这样的结构允许我们在对数时间内移除 \(x\) 和 \(y\),并重新插入新节点 \(x + y\)。
在每一步中,数组中位于偶数索引上直到 \(y\) 值的权重形成了一个递减序列,位于奇数索引位的权重形成另一个递减序列。因此,重新插入 \(x+y\) 的位置可以通过在对数时间内对这两个递减序列使用平衡树执行两次二分查找找到。通过从前一个三元组 \(z\) 值开始的线性顺序搜索,我们可以在总线性时间复杂度内执行对满足 \(x \leq z\) 的第一个位置的搜索。
如果实在不会平衡树,vector 的 insert 和 erase 操作也是个不错的选择呢!
Garsia-Wachs 算法的总时间复杂度为 \(O(n\log n)\),时间复杂度证明?我只能说,学 OI 记住结论就好了,证明,那是数学要考虑的事,不是 OI 要考虑的事 考试又不会让你证明时间复杂度
至于正确性的证明我也不会= =,这个算法应用范围十分有限,因此学的价值不是很高,“会用” + “知道有这个东西” 就行了
关于上面那道引入题的代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll read() {
ll x = 0;
int fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
const int N = 4e4 + 5;
int n, ans;
vector<int> g;
int merge() {
int k = g.size() - 2;
for (int i = 0; i <= k; ++ i) {
if (g[i] <= g[i + 2]) {
k = i;
break;
}
}
int tmp = g[k] + g[k + 1];
g.erase(g.begin() + k);
g.erase(g.begin() + k);
int t = -1;
for (int i = k - 1; i >= 0; -- i) {
if (g[i] >= tmp) {
t = i;
break;
}
}
g.insert(g.begin() + t + 1, tmp);
return tmp;
}
int main() {
n = read();
for (int i = 1; i <= n; ++ i) {
g.emplace_back(read());
}
for (int i = 1; i < n; ++ i) {
ans += merge();
}
printf("%d\n", ans);
return 0;
}
「学习笔记」Garsia-Wachs 算法的更多相关文章
- 「学习笔记」Min25筛
「学习笔记」Min25筛 前言 周指导今天模拟赛五分钟秒第一题,十分钟说第二题是 \(\text{Min25}\) 筛板子题,要不是第三题出题人数据范围给错了,周指导十五分钟就 \(\text{AK ...
- 「学习笔记」字符串基础:Hash,KMP与Trie
「学习笔记」字符串基础:Hash,KMP与Trie 点击查看目录 目录 「学习笔记」字符串基础:Hash,KMP与Trie Hash 算法 代码 KMP 算法 前置知识:\(\text{Border} ...
- 「学习笔记」FFT 之优化——NTT
目录 「学习笔记」FFT 之优化--NTT 前言 引入 快速数论变换--NTT 一些引申问题及解决方法 三模数 NTT 拆系数 FFT (MTT) 「学习笔记」FFT 之优化--NTT 前言 \(NT ...
- 「学习笔记」FFT 快速傅里叶变换
目录 「学习笔记」FFT 快速傅里叶变换 啥是 FFT 呀?它可以干什么? 必备芝士 点值表示 复数 傅立叶正变换 傅里叶逆变换 FFT 的代码实现 还会有的 NTT 和三模数 NTT... 「学习笔 ...
- 「学习笔记」Treap
「学习笔记」Treap 前言 什么是 Treap ? 二叉搜索树 (Binary Search Tree/Binary Sort Tree/BST) 基础定义 查找元素 插入元素 删除元素 查找后继 ...
- 「学习笔记」平衡树基础:Splay 和 Treap
「学习笔记」平衡树基础:Splay 和 Treap 点击查看目录 目录 「学习笔记」平衡树基础:Splay 和 Treap 知识点 平衡树概述 Splay 旋转操作 Splay 操作 插入 \(x\) ...
- 「学习笔记」wqs二分/dp凸优化
[学习笔记]wqs二分/DP凸优化 从一个经典问题谈起: 有一个长度为 \(n\) 的序列 \(a\),要求找出恰好 \(k\) 个不相交的连续子序列,使得这 \(k\) 个序列的和最大 \(1 \l ...
- 「学习笔记」ST表
问题引入 先让我们看一个简单的问题,有N个元素,Q次操作,每次操作需要求出一段区间内的最大/小值. 这就是著名的RMQ问题. RMQ问题的解法有很多,如线段树.单调队列(某些情况下).ST表等.这里主 ...
- 「学习笔记」递推 & 递归
引入 假设我们想计算 \(f(x) = x!\).除了简单的 for 循环,我们也可以使用递归. 递归是什么意思呢?我们可以把 \(f(x)\) 用 \(f(x - 1)\) 表示,即 \(f(x) ...
- 「学习笔记」min_25筛
前置姿势 魔力筛 其实不看也没关系 用途和限制 在\(\mathrm{O}(\frac{n^{0.75}}{\log n})\)的时间内求出一个积性函数的前缀和. 所求的函数\(\mathbf f(x ...
随机推荐
- DOM选择器之元素节点选择器
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- ArcGIS倾斜摄影无法加载找不到nodes节点
倾斜摄影无法加载,在fiddler请求中,nodes/root请求失败,如:http://10.0.7.173:6080/arcgis/rest/services/Hosted/xm4490/Scen ...
- EF Core从TPH迁移到TPT
Intro EF Core支持多种方式处理具有继承关系的表,现在支持TPH.TPC(EF Core 7).TPT,具体的实现方式可以参考官方文档和这篇文章. 大致总结一下不同的方式的区别: TPH:所 ...
- hdfs集群的扩容和缩容
目录 1.背景 2.集群黑白名单 3.准备一台新的机器并配置好hadoop环境 3.1 我们现有的集群规划 3.2 准备一台新的机器 3.2.1 查看新机器的ip 3.2.2 修改主机名和host映射 ...
- SQL里按照年月日分组统计
Mysql中使用DATE_FORMAT函数实现是相对简单的. 根据format字符串格式化date值.下列修饰符可以被用在format字符串中: %M 月名字(January--December) % ...
- window安装openslide库
下载openslide二进制文件: 链接:https://openslide.org/download/ 将下载好的ZIP文件解压到Anaconda的Library目录下(你也可以选择自己喜欢的目录 ...
- python之爬虫一
python爬虫学习 1爬虫室什么 网络爬虫(Web Spider)又称"网络蜘蛛"或"网络机器人",它是一种按照一定规则从 Internet 中获取网页内容的 ...
- c# 异步进阶———— 自定义 taskschedule[三]
前言 我们知道我们的task async 和 await 是基于线程池进行调度的. 但是async 和 await 也就是使用了默认的task调度,让其在线程池中运行. 但是线程池是榨干机器性能为本质 ...
- 执行sql报lock wait timeout exceeded; try restarting transaction
mysql查询时候报错: Lock wait timeout exceeded; try restarting transaction 译文:锁等待超时;试着重新启动事务 被锁了,需要解锁. 1.in ...
- windows下MinGW编译ffmpeg
windows下MinGW编译ffmpeg 1.官网下载MinGW并安装 1)下载 ,下载网址: https://sourceforge.net/projects/mingw/files/ ...