从《Cash》谈一类分治算法的应用cdq
分治算法及其典型应用

分治算法及其典型应用
分治算法是一种重要的算法设计策略,它将一个大问题分解成若干个规模较小的子问题,然后递归地解决这些子问题,最后将它们的解合并起来,得到原问题的解。
分治算法在计算机科学和算法设计中有着广泛的应用,可以解决许多实际问题,下面将介绍一些典型的应用。
1. 排序算法。
分治算法在排序算法中有着重要的应用。
其中最著名的就是归并排序和快速排序。
在归并排序中,算法将数组分成两个子数组,分别进行排序,然后合并这两个有序的子数组。
而在快速排序中,算法选择一个基准值,将数组分成两个子数组,分别小于和大于基准值,然后递归地对这两个子数组进行排序。
2. 搜索算法。
分治算法也可以用于搜索问题,例如二分搜索算法。
在这种算法中,将搜索区间分成两个子区间,然后递归地在其中一个子区间中进行搜索,直到找到目标元素或者子区间为空。
3. 求解最大子数组问题。
最大子数组问题是一个经典的动态规划问题,也可以用分治算法来解决。
算法将数组分成两个子数组,分别求解左右子数组的最大子数组,然后再考虑跨越中点的最大子数组,最后将这三种情况的最大值作为整个数组的最大子数组。
4. 矩阵乘法。
分治算法也可以用于矩阵乘法。
在矩阵乘法中,算法将两个矩阵分成四个子矩阵,然后递归地进行矩阵乘法,最后将四个子矩阵的结果合并成一个矩阵。
总的来说,分治算法是一种非常重要的算法设计策略,它在许多实际问题中有着广泛的应用。
通过将一个大问题分解成若干个规模较小的子问题,然后递归地解决这些子问题,最后将它们的解合并起来,我们可以高效地解决许多复杂的问题。
如何应用分治算法求解问题

如何应用分治算法求解问题分治算法,英文名为Divide and Conquer Algorithm,是一种高效的算法设计策略,在计算机科学中有着广泛的应用。
该算法将一个大问题分解成多个小问题,各自独立地解决,再将结果合并起来得到最终结果。
在本文中,我们将阐述如何应用分治算法求解问题,并通过几个实例来具体说明该算法的应用。
一、分治算法的原理分治算法的核心思想是将一个大问题分解成若干个小问题来解决,然后将这些小问题的解组合起来生成大问题的解。
其具体步骤如下:1. 分解:将原问题划分成若干个规模较小的子问题。
2. 解决:递归地解决每个子问题。
如果子问题足够小,则直接求解。
3. 合并:将所有子问题的解合并成原问题的解。
分治算法的主要优点在于它可以有效地缩小问题规模,从而缩短整个算法的执行时间。
另外,该算法天然适用于并行计算,因为每个子问题都是独立求解的。
二、分治算法的应用分治算法在各种领域都有广泛应用,包括数学、自然科学、计算机科学等。
以计算机科学领域为例,分治算法常常用于解决以下类型的问题:1. 排序问题2. 查找问题3. 字符串匹配问题4. 最大子序列和问题5. 矩阵乘法问题6. 图形问题下面我们将一一讲解这些问题的分治算法实现。
1. 排序问题排序问题是在一组数据中将其按指定规律进行排列的问题。
在计算机科学中,排序算法是十分重要的一类算法。
其中,分治算法由于其高效性和可并行性被广泛应用。
常用的分治排序算法包括归并排序和快速排序。
归并排序的基本思想是将待排序元素以中心点为界分成两个序列,对每个序列进行排序,然后将两个序列合并成一个有序序列;而快速排序则利用了分割的思想,通过每次选取一个元素作为“轴点”,将数组分成小于轴点和大于轴点的两部分,对这两部分分别进行快速排序。
2. 查找问题查找问题是在一组数据中寻找某个元素的问题。
分治算法在查找问题中的应用主要体现在二分查找中。
在二分查找中,我们首先将已排序的数组分成两半,在其中一半中查找目标值。
分治算法

问题S1 问题
问题S 问题 2
……
问题S 问题 i 子问题求 解
……
问题Sn 问题
Sபைடு நூலகம்的解
S2的解
……
Si的解
……
Sn的解
子集解的合并
问题S S的解 的解 问题
分治思想
由分治法所得到的子问题与原问题具有相同的类型。 由分治法所得到的子问题与原问题具有相同的类型。如 果得到的子问题相对来说还太大, 果得到的子问题相对来说还太大,则可反复使用分治策 略将这些子问题分成更小的同类型子问题, 略将这些子问题分成更小的同类型子问题,直至产生出 不用进一步细分就可求解的子问题。 不用进一步细分就可求解的子问题。 分治求解可用一个递归过程来表示。 分治求解可用一个递归过程来表示。 要使分治算法效率高,关键在于如何分割?一般地, 要使分治算法效率高,关键在于如何分割?一般地,出 于一种平衡原则,总是把大问题分成K个规模尽可能相 于一种平衡原则,总是把大问题分成 个规模尽可能相 等的子问题,但也有例外, 等的子问题,但也有例外,如求表的最大最小元问题的 算法, 的子表L1和 算法,当n=6时,等分定量成两个规模为 的子表 和 = 时 等分定量成两个规模为3的子表 L2不是最佳分割。 不是最佳分割。 不是最佳分割
分治过程
比较过程
分析
从图例可以看出,当有 个金块的时候 方法1需 个金块的时候, 从图例可以看出,当有8个金块的时候,方法 需 要比较15~16次,方法 只需要比较 次,那么形成 只需要比较10次 那么形成 要比较 次 方法2只需要比较 比较次数差异的根本原因在哪里? 比较次数差异的根本原因在哪里 其原因在于方法2对金块实行了分组比较 对金块实行了分组比较。 其原因在于方法 对金块实行了分组比较。 对于N枚金块 我们可以推出比较次数的公式: 枚金块, 对于 枚金块,我们可以推出比较次数的公式: 假设n是 的次幂 的次幂, 为所需要的比较次数。 假设 是2的次幂,c(n)为所需要的比较次数。 为所需要的比较次数 方法1: 方法 : c(n)=2n-1 方法2: 方法 :c(n) = 2c(n/2 ) + 2。 。 使用迭代方法可知c(n) = 3n/2 - 2。在本 由c(2)=1, 使用迭代方法可知 。 例中,使用方法2比方法 少用了2 %的比较次数。 比方法1少用了 例中,使用方法 比方法 少用了 5%的比较次数。
分治算法及其应用

分治算法及其应用分治算法是一种常见的算法思想,它主要的思想是将一个问题分解为多个子问题,分别求解后再将其合并为原问题的解。
分治算法在计算机科学中有着广泛的应用,例如排序、搜索、图像处理等领域。
1.基本思想分治算法的基本思想是将一个大问题分解为若干个相似的子问题,并递归地求解这些子问题,最后将结果合并成原问题的解。
例如,在求解一个大数组的排序问题时,可以先将数组分成两个子数组,再对每个子数组进行排序,最后将两个子数组合并成一个有序的数组。
2.实现分治算法的实现通常采用递归的方法。
在递归过程中,每次将大问题分解为若干个子问题,然后将子问题递归地求解,直到子问题无法再分解,然后进行合并。
以归并排序为例,该算法分为分解、解决和合并三个过程。
首先将一个大数组分解为两个相等的子数组,然后递归地对子数组进行排序,最后将两个有序的子数组合并成一个有序的数组。
3.算法复杂度分治算法的复杂度主要取决于子问题规模和分解子问题的方式。
通常情况下,分治算法的时间复杂度可以表示为:T(n) = aT(n/b) + f(n)其中,a是每个递归过程的次数,b是子问题规模,f(n)是除了递归外的其他操作的复杂度。
根据主定理,当a>b^d时,算法复杂度为O(n^logb a),否则算法复杂度为O(n^d)。
4.应用分治算法在计算机科学中有广泛应用,例如排序、搜索、图像处理等领域。
归并排序、快速排序、堆排序等都是基于分治算法实现的排序算法。
在搜索领域,二分查找算法就是一种基于分治思想的搜索算法。
在图像处理领域,分治算法可以用来实现图像的分割、匹配等操作。
例如,可以将一幅图像分解成若干个子图像,然后对每个子图像进行处理,最后将处理结果合并成原图像的结果。
总之,分治算法是一种非常重要的算法思想,它能够解决很多复杂的问题,并且在实际应用中取得了很好的效果。
二分算法与分治的关系

二分算法与分治的关系
二分算法和分治算法都是一种解决问题的方法,它们之间有一定的关系,但又有着明显的区别。
首先,二分算法是一种在有序数组中查找特定元素的算法。
它通过将数组分成两半,然后确定目标值可能在哪一半,不断缩小搜索范围直到找到目标值或者确定目标值不存在。
二分算法的关键在于每次都将搜索范围缩小一半,因此时间复杂度为O(log n)。
这种算法通常用于快速查找有序数组中的元素,比如二分查找。
而分治算法则是一种解决问题的思想,它将一个大问题分解成多个相似的小问题,然后分别解决这些小问题,最后将它们的解合并起来得到大问题的解。
分治算法通常包括三个步骤,分解(Divide)、解决(Conquer)、合并(Combine)。
经典的分治算法有归并排序和快速排序等。
二分算法可以被看作是分治算法的一种特殊情况,因为它也是将问题分解成两个子问题,然后递归地解决这些子问题。
但与一般的分治算法不同的是,二分算法并不需要将子问题的解进行合并,而是通过比较来确定最终的结果。
总的来说,二分算法是一种特殊的分治算法,它们都是解决问题的有效方法,但适用的场景和具体实现方式有所不同。
在实际应用中,我们需要根据具体的问题特点来选择合适的算法。
分治算法

65 97
13 76
38 49 65 97
13 27 76
13 27 38 49 65 76 97
黑盒划分典型问题—合并排序
合并排序算法改进
从分治过程入手,容易消除mergeSort算法中的递归 调用
49 38 65 97 76 13 27
38 49
65 97
13 76
27
38 49 65 97
题的解,自底向上逐步求出原来问题的解。
T(n)
=
n
递归的概念
由分治法产生的子问题往往是原问题的较小模式,这 就为使用递归技术提供了方便。在这种情况下,反复 应用分治手段,可以使子问题与原问题类型一致而其 规模却不断缩小,最终使子问题缩小到很容易直接求 出其解。这自然导致递归过程的产生。
直接或间接地调用自身的算法称为递归算法。用函数 自身给出定义的函数称为递归函数。
黑盒划分典型问题—合并排序
【例5】合并排序
任务描述:任意给定一包含n个整数的集合,把n个整数按升序排列。 输入:每测试用例包括两行,第一行输入整数个数,第二行输入n个整 数,数与数之间用空格隔开。最后一行包含-1,表示输入结束。 输出:每组测试数据的结果输出占一行,输出按升序排列的n个整数。 样例输入:
13 27 76
13 27 38 49 65 76 97
黑盒划分典型问题—合并排序
黑盒划分典型问题—合并排序
合并排序算法改进
从分治过程入手,容易消除mergeSort算法中的递归调用 自然合并排序
49 38 65 97 76 13 27
49
38 65 97
76
13 27
38 49 65 97
黑盒划分典型问题—逆序对问题
分治思想——精选推荐

分治思想
分治
基本思想及策略
分治法的思想是:将⼀个难以直接解决的⼤问题,分割成⼀些规模较⼩的相同问题,以便逐个解决,分⽽治之。
分治策略是:对于⼀个规模为n的问题,若该问题可以容易地解决(⽐如说规模n较⼩)则直接解决,否则将其分解为k个规模较⼩的⼦问题,这些⼦问题互相独⽴且与原问题形式相同,递归地解这些⼦问题,然后将各⼦问题的解合并得到原问题的解。
这种算法设计策略叫做分治法。
使⽤场景
分治法所能解决的问题⼀般具有以下⼏个特征:
(1)该问题的规模缩⼩到⼀定的程度就可以容易解决。
(2)该问题可以分解为若⼲个规模较⼩的相同问题,该问题有最优⼦结构的性质。
(3)利⽤该问题分解出的⼦问题可以合并成该问题的解。
(4)该问题所分解出的各个⼦问题是相互独⽴的,即⼦问题之间不包含公共⼦问题。
第⼀条特征是绝⼤多数问题都可以满⾜的,因为问题的计算复杂性⼀般随着问题规模的增加⽽增加。
第⼆条特征是应⽤分治法的前提,此特征反映了递归思想的应⽤。
第三条是关键,能否利⽤分治法完全取决于问题是否具有第三条特症,如果具备了第⼀条和第⼆条特征,⽽不具备第三条特征,可以考虑使⽤贪⼼法或者动态规划。
第四条特征涉及到分⽀法的效率。
(Day1)cdq分治相关

[WF2011] MACHINE WORKS
Fi = Max (F[i-1], F[j]-P[j]+R[j]+G[j]*(D[i]-D[j]-1))
F[j]>P[j]
令A[j]=F[j]-P[j]+R[j]-G[j]*D[j]-G[j] 那么F[i] = Max(F[i-1],A[j]+G[j]*D[i])
Solve(L,R)
Solve(l,mid) 处理[l,mid]中操作对[mid+1,r]中操作的影响 Solve(mid+1,r)
如何处理?
[BOI2007] MOKIA
前半部分的Add对后半部分的Query造成的影响 给定带权点集P=(Xi,Yi),Q个询问(x0,y0,x1,y1),对 于每个询率D[i]是不变的,因此可以对整个[F1,Fn] 进行分治。
复杂度O(nlogn),和平衡树维护凸壳同阶
[WF2011] MACHINE WORKS
F[i] = Max(F[i-1],A[j]+G[j]*D[i])
在平面上有若干直线y=G[j]*x+A[j] 维护一个直线集,支持以下两类操作
线段树套平衡树/可持久化线段树 O(nlog^2n)
3D PARTIAL ORDER
没有操作1的情况
[VIOLET 3]天使玩偶
定义操作Solve(l,r),处理[l,r]之间的询问 Solve(l,r)
Solve(l,mid) 考虑[l,mid]中的点对[mid+1,r]中询问的影响 Solve(mid+1,r)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
例一.货币兑换(Cash)1 问题描述
小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A 纪念券(以下简称 A 券)和 B 纪念券(以下简称 B 券) .每个持有金券的顾 客都有 一个自己的帐户.金券的数目可以是一个实数. 每天随着市场的起伏波动,两种金券都有自己当时的价值,即每一单位金 券 当天可以兑换的人民币数目.我们记录第 K 天中 A 券和 B 券的价值 分别为 AK 和 BK(元/单位金券) . 为了方便顾客, 金券交易所提供了一种非常方便的交易方式: 比例交易法.比 例交易法分为两个方面: A) 卖出金券: 100]内的实数 OP 作为卖出比例, 顾客提供一个[0, 其意 义 为:将 OP%的 A 券和 OP%的 B 券以当时的价值兑换为人民币; B) 买入金券:顾客支付 IP 元人民币,交易所将会兑换给用户总价值为
2008 年信息学国家集训队作业
雅礼中学
陈丹琦
[l, r]这一段按 f[]值排序. End Procedure 至此,问题已经基本解决.时间复杂度为 T(n) = 2T(n/2) + O(n),因此算法的 时间复杂度为 O(nlog2n),NOI2007 的测试数据最慢的测试点 0.2s,是一个相当 优秀的算法. 我们比较一下分治算法和用平衡树维护决策的方法:时间复杂度均为 O(nlog2n) ,空间复杂度平衡树为 O(n) ,分治为 O(nlog2n) ( 预处理 -a[i]/b[i] 需要 O(nlog2n)的空间).但是编程复杂度却差别非常大,分治算法实现起来相当简单, 对于考场来说无疑是一个非常好的方法. 在编程复杂度非常高的情况下, 动态规划维护决策与分治思想很好的结合起 来从而降低了编程复杂度,无疑是“柳暗花明又一村” .这种分治思想主要体现 在将不断变化的决策转化成一个不变的决策集合, 将在线转化为离线. 下面我们
雅礼中学
陈丹琦
集(f [j], g[j]),f [j]是单调递增的,相邻两个点的斜率是单调递减的.每次在平衡 树中二分查找与-a[i] / b[i]最接近的两点之间的斜率. 这样动态规划的时间复杂度就降低为 O(nlog2n),但是维护凸线的平衡树实 在不容易在考场中写对, 编程复杂度高, 不易调试(我的 Splay 代码有 6k 多). 这 个问题看上去只能用高级数据结构来维护决策的单调性, 事实上我们可以利用分 治的思想来提出一个编程复杂度比较低的方法: 对于每一个 i,它的决策 j 的范围为 1~i-1.我们定义一个 Solve 过程: Solve(l, r)表示对于的 l ≤ i ≤ r, 用 l ≤ j ≤ i-1 的决策 j 来更新 f [i]的值. 这样我们的 目标就是 Solve(1, n):可以先 Solve(1, n/2)后计算出 f [1] .. f[n/2],那么 1~n/2 的每 一个数一定是 n/2+1~n 的每个 i 的决策,用 1~n/2 的决策来更新 n/2+1~n 的 f[i] 值后 Solve(n/2+1, n).这恰好体现的是一种分治的思想: 用 1~n/2 的决策来更新 n/2+1~n 的 f[i]值:类似用平衡树的方法,我们可以 对 1~n/2 的所有决策建立一个凸线,对 n/2+1~n 的所有 i 按照-a[i] / b[i]从大到小 排序,凸线的斜率是单调的,-a[i]/b[i]也是单调的,这样我们就可以通过一遍扫 描来计算出对于每一个 i 在 1~n/2 里面最优的决策 j. 现在面临的问题是如何对于一段区间[l, r]维护出它的凸线:由于 f []值是临 时计算出来的,我们只需要递归的时候利用归并排序将每一段按照 f []值从小到 12121212122111 大排序,凸线可以临时用一个栈 O(n)计算得出.下面给一个分 治算法的流程: 由于-a[i] / b[i]是已知的,不像 f [i]是临时计算得出的.因此可以利用归并排 序预处理,计算每一段[l, r]按照-a[i] / b[i]排序后的 i. Procedure Solve(l, r) If l = r Then 更新 ans,利用已经计算好的 l 的最优决策 k,计算 f [l]值,Exit Mid ← (l + r) / 2 Solve(l, mid -1) 对[l, mid-1]这一段扫描一遍计算出决策的凸线,由于[mid+1 .. r]这一段以 -a[i] / b[i]的排序在预处理已经完成,因此只需要扫描一遍更新[mid + 1 .. r] 的最优决策. Solve(mid+1, r) 利用[l, mid-1]已排好序的 f []值和[mid+1, r]已排好序的 f []值归并排序将
例二.Mokia2 问题描述
有一个 W * W 的棋盘,每个格子内有一个数,初始的时候全部为 0.现在要 求维护两种操作: 1) Add:将格子(x, y)内的数加上 A. 2) Query:询问矩阵(x0, y0, x1, y1)内所有格子的数的和. 数据规模:操作 1) ≤ 160000,操作 2) ≤ 10000, 1 W 2 000 000 .
算法分析
这个问题是 IOI 2000 Mobile 的加强版: Mobile 中 W≤1000, 就可以利用二树 状数组在 O(log22n)的时间复杂度内维护出操作 1)和操作 2). 这个问题中 W 很大, 开二维树状数组 O(W2)的空间显然吃不消,考虑使用动态空间的线段树,最多可 能达到操作次数 * (log2W)2 个节点, 也相当大了. 考虑使用分治思想来解决问题: 将 操作 1) 和操作 2) 按顺序看成是一个个事件,假设共有 Tot 个事件,
2
Balkan Olympiad in Informatics, 2007
2008 年信息学国家集训队作业
雅礼中学
陈丹琦
Tot≤170000.类似例题一,我们定义 Solve(l, r)表示对于每一个 Query 操作的事 件 i, 将 l ..i-1 的 Add 操作的所有属于 i 的矩形范围内的数值累加进来.目标是 Solve(1, n). 假设计算 Solve(L, R),递归 Solve(L, Mid) , Solve(Mid + 1, r) 后,对 L .. Mid 的所有 Add 操作的数值累加到 Mid + 1 .. R 的所有匹配的 Query 操作的矩形中. 后面这个问题等价于:平面中有 p 个点,q 个矩形,每个点有一个权值,求 每个矩形内的点的权值之和. 这个问题只需要对所有的点以及矩形的左右边界进 行排序, 用一维树状数组或线段树在 O((p+q)log2W)的时间复杂度即可维护得出. 因此问题的总的时间复杂度为 O(Tot*log2Tot*log2W) ,不会高于二维线段树的 O(Tot*log2W*log2W)的时间复杂度. 上述这个算法无论是编程复杂度还是空间复杂度都比使用二维线段树优秀, 分治思想又一次得到了很好的应用.在这个问题中,利用分治思想我们将一个在 线维护的问题转化成一个离线问题, 将二维线段树解决的问题降维用一维线段树 来解决,使得问题变得更加简单.
总结
【例题一】是一个数据结构维护动态规划决策的问题, 【例题二】为一个数 据结构维护数据信息的问题. 我们巧妙地使用分治思想,将在线维护的问题转化 为离线问题,将变化的数据转化为不变的数据,使得问题解决更加的简单.
IP 的金券, 并且, 满足提供给顾客的 A 券和 B 券的比例在第 K 天恰好为 RateK;
例如,假定接下来 3 天内的 Ak、Bk、RateK 的变化分别为: 时间 Ak Bk RAtek 1 1 1 第一天 1 2 2 第二天 第三天 2 2 3 假定在第一天时,用户手中有 100 元人民币但是没有任何金 券. 用户可以执行以下的操作:
2008 年信息学国家集训队作业
雅礼中学
陈丹琦
从《Cash》谈一类分治算法的应用
分治算法的基本思想是将一个规模为 N 的问题分解为 K 个规模较小的子问 题,这些子问题相互独立且与原问题性质相同.求出子问题的解,就可得到原问 题的解.分治算法非常基础,但是分治的思想却非常重要,本文将从今年 NOI 的一道动态规划问题 Cash 开始谈如何利用分治思想来解决一类与维护决策有关 的问题:
注意到,同一天内可以进行多次操作. 小 Y 是一个很有经济头脑的员工,通过较长时间的运作和行情测算, 他已经 知道了未来 N 天内的 A 券和 B 券的价值以及 Rate.他还希望 能够计算出来,如 果开始时拥有 S 元钱,那么 N 天后最多能够获得多少元 钱.
算法分析
不难确立动态规划的方程: 设 f [i]表示第 i 天将所有的钱全部兑换成 A, B 券, 最多可以得到多少 A 券. 很 容易可以得到一个 O(n2)的算法: f [1]←S * Rate[1] / (A[1] * Rate[1] + B[1]) Ans←S For i ← 2 to n For j ← 1 to i-1 x ← f [j] * A[i] + f [j] / Rate[j] * B[i] If x > Ans Then Ans ← x End For f [i] ← Ans * Rate[i] / (A[i] * Rate[i] + B[i]) End For Print(Ans) O(n2)的算法显然无法胜任题目的数据规模.我们来分析对于 i 的两个决策 j 和 k,决策 j 比决策 k 优当且仅当: (f [j] – f [k]) * A[i] + (f [j] / Rate[j] – f [k] / Rate[k]) * B[i] > 0. 不妨设 f [j] < f [k],g[j] = f [j] / Rate[j],那么 (g[j] – g[k]) / (f[j] – f[k]) < -a[i] / b[i]. 这样我们就可以用平衡树以 f [j]为关键字来维护一个凸线, 平衡树维护一个点