【QBXT】学习笔记——Day8分治

今天一早上就睡晚了呢0.0,七点半才起床
今天讲的可是分治啊!

分治的原理就是将一个大问题分成两个子问题,子问题再继续分下去。
将简单的子问题处理完以后和并起来得到大问题的答案。
divideconquerreduce

Concuerreny 问题
给出n个数,计算它们的和,要求速度快。
如果普通的算法就是一个个加,递归层数4层。
并行算法:解决两个或多个子问题时,同时扔到两个或更多CPU上运行。
运行的时间只是解决一个子问题数量。显然运行速度与递归层数有关。

接下来给出一个数组,求前缀和。看这篇博文0.0

接下来要求设计一个并行的排序算法

双调序列:先单调递增,再单调递减的序列(或反过来)
双调序列排序:左右分成两段,同时从左到右枚举,小的放左边,得到两个双调序列。
并且:左边的双调序列元素小于右侧的双调序列所有元素。
迭代这个过程,长度为2的双调序列=有序。
老师讲这个东西,先画了一个倒着的V,然后把V的右边平移,整个序列是一个X
我们用一个扫描线,从左往右比较上下两个元素,将大的元素放在右,小的放左。

如何得到一个双调序列?我们同样分治
首先将第1/2组从小到大排序,3/4组从大到小排,5/6组从小到大…
这样将相邻两组放在一起就是一个双调序列,然后我们再安装上面的方法。
这样一直排下去,就可以得到一个最大的双调序列。
这个复杂度在并行的情况下应该是 O(log2n)
这个东西叫做排序网络。

主定理- -

然后我们就要开始解题了:
Maximizing Unimodal Arrays双调序列最大值
显然将这个序列差分一下我们就可以二分了233
但是上面是错的,因为如果有相同元素怎么办呢?可能会GG。
三分法!
其实就是比较 a[mid] a[mid+1]
<则递归右边,>则递归左边,=则两边都递归。
如果全部数都相等就GG了。

Common Algorithms
目标:找到第 k 大的数。
这个东西和排序有点不一样233,只用找到就行了。
简单的分治算法:选择一个主元,我们递归左边,看左边有多少个数比主元大,设为m
m<=k ,则在左边,否则在右边,往下一层找即可。
那么问题来了——我们如何找到这个主元?
可以随机!但是这个东西是被很好解决了的:
FindMedian算法:
把数组分成 n5 份,找到每一份的中位数。递归调用中位数算法,找到中位数的中位数。
然后最后用这个中位数作为主元即可。这样分完以后,两个区间最小是原大小的 310
根据主定理 T(n)=T(n5)+T(7n10)+O(n)=O(n)
这玩意的发明人真是牛啊- -(不想列了)
不过这个东西也不好在这写是吧,那么我们还是直接随机吧。
随机炸到 n2 的概率是: 2(n1)n! ,应该还好吧,这个以后可以推算0.0

Tiling with Triominoes
给定一个 n×n(n=2k) 的矩阵,使用三格的L形骨牌进行覆盖。
问最优方案里,有多少的位置不能被覆盖到,覆盖方案是多少。

首先假定右上角这个格子不能被覆盖,分开这个矩阵,变成了 n2×n2 的矩阵
这样我们在中心的位置放一个L的骨牌,显然左上左下和右下,经过归纳后,都可以放完。
而左上角显然是一个子问题。归纳下去,我们可以得到一个方案,使右上角不覆盖。
将这个结论推广,不论我们选中哪一个格子不被覆盖,我们都可以构造一个方案出来。

Integer Multiplication
高精度乘法,给定两个长度为n的整数,求他们的乘积。
我们可以用FFT,当然更好的是用65536进制,因为进位可以用位运算。
这里写图片描述
解法就是这样,懒得自己码了。

Similar Trick:Strassen Algorithm
讲了矩阵乘法的优化分块??然后就可以降低复杂度,但是没用。

CF888E
给定n个正整数 ai 和一个模数 m 。找到一个子集B,最小化:
(bBb)modm
n<=35,ai,m<=1e9
看起来很难,其实就是爆搜。Meet in the Middle想法
爆搜前一半,爆搜后一半然后合并。
前一半的mod数弄出来以后排序,然后对于后一半的每个mod数在前面二分找就行了。

CF868F
给一个长度为 n 的序列ai,现在要求分成 k 块,
每一块的代价是“值相同但是位置不同数对个数”,求最小总代价。
n<=105,2<=k<=min(n,20),ai<=n

n2k 的方法很显然了
f(n,k)=min(f(i,k1)+cost(i+1,k))
显然 f(n,k) 这个函数关于k是单调的
考虑计算两个值 f(i,k) f(j,k) i j 是两个决策点(即最后划分点),
显然决策点的位置也是单调的。
考虑i有两个决策点 a b,且 a<b ,决策点前的值相等。
如果我们在后面加一个元素,那么扩展的区间的 cost , a 显然是不小于b的。
这样子我们可以大力分治。

考虑这一类问题的做法:
如果现在分治区间L M R,分治区间L’ M’ R’,那么已知L’和R’,如何得到M’
事实上我们从L’到R’直接扫一次就行了。

BZOJ3263:三元逆序对(权限题)
给定 n 个三元组(Ai,Bi,Ci),找出所有的i,j,使得三元内严格小于
n<=105,Ai,Bi,Ci<=2105
偏序题就是每一维用一个数据结构。
三维就是用排序干掉一维,然后CDQ一维,再树状数组一维。

对于这题,我们按照 Ai 排序,考虑对长度分治,每次考虑[L,R]区间内的答案。
递归处理两边,考虑所有跨越中间点的数对,满足i在左区间,j在右区间。
我们从小到大枚举 Bi ,用线段树维护 Ci
即每遇到左边的一个 Bi ,我们就将 Ci 这个值放进线段树(维护每个值出现多少次)。
如果遇到右边的一个 Bi ,我们就求一下这棵线段树在 1Ci 的和。

BZOJ3456贸易线路
求点数为n的简单无向图的个数。简单图:无重边,有自环。 n<=105

戳这里
递推式是 fi=2C2ii1j=1fjCj1i12C2ij
然后左右两边同除 (n1)!
fi(i1)!=2C2i(i1)!i1j=1fj2C2ij(j1)!(ij)!
ij=1fj(j1)!2C2ij(ij)!=2C2i(i1)!
那么这是一个卷积的形式,我们令:
A=ni=1fi(i1)!xi
B=ni=02C2ii!xi
C=ni=12C2i(i1)!xi
AB=C
那么 ACB1(mod xn+1)
也就是多项式求逆。

ZOJ 3874 Permutation Graph是和上面那题差不多的练习题。

Balkan OI 2007:Mokia
有一个 W×W 的棋盘,每个格子有一个数,初始为0。
维护两种操作: Add(x,y)AQuery(x,y,xx,yy) 询问矩阵和

显然可以用二维线段树做。
当然也可以用CDQ分治做。
实际上我们只用考虑前一半操作对后一半操作的影响。
问题转化为给定点集 (x,y,A) ,查询若干个矩阵内的点。

BZOJ2716天使玩偶
维护一个二维平面,支持如下两种操作:
1.插入一个点 (x,y)
2.询问一个点 (xq,yq) 最近的点,曼哈顿距离
|x,y|<=105,q<=105

首先分治,考虑左半边已经加入的点对右半边的影响。
dis(i,q)=|xixq|+|yiyq|
曼哈顿距离常用套路,分四种情况讨论。
先解决 dis1(i,q)=(xixq)+(yiyq)
求满足: xi>xq,yi>yq ,且 xi+yi 最小的点。
带权为 xi+yi 的点集,二维区间最值。

上午讲的东西,其实很大程度上是处理一种”依赖关系“
即分治时如何处理前面对后面的影响。
但是上午讲的东西确实超乎了我的认知233

Day8 1.22NIGHT

今天考试很烦啊,T1T2都是秒的题,然后都挂了。
T1老师讲了一个置换群的问题:
一个置换的n次方就代表这个置换进行n次。然而并没有什么用。
倍增乱搞写挂了??
没有判0。

T2写分治,然后又写挂了???但是本地测是过的(上面是RE)
听说 O(qe) 可过。然而不关我事啊
如果没有去掉一个物品的限制,就是一个简单背包。

rqy神犇的思路是对整个区间进行分块,然后每个块背包,再合并。

老师的算法是这样的:
考虑已经有一个背包,那么现在要加入一个新的物体。
复杂度是 O() ,这是十分简单的,但删除是很困难的。
考虑分治算法。
假设现在要求 12 34 这区域的dp值,
其他区域的dp值一定使用到这个区域的dp值。
这样我们每次分到一部分时,我们将所有外部的dp值都传到这个部分。
然后再进行合并。
也就是说,对于每个区块,我们将右边的dp值丢到左边去算,
同样将左边的dp丢到右边去算。

我的思路也是分治,同样是将一部分的dp值丢到另一边然后dp。
但是在写法上有点不同。
用单调队列优化以后复杂度应该是 O(nlogn)
写挂了很可耻可耻可耻。并没有写挂。

rqy的T3的40pt是这样的:
首先点——边——点的最短距离就是作对称点然后连直线求交。
对于有两条边(即点——边——边——点)的情况也是一样的。
然后就这样水,不断按多边形的顺序跑。
为什么呢?因为跑的路线一定是不交的(如果交一定可以替换为更优的)

但是这样做的时候有个问题,因为可能连起来的直线不在线段上。

正解在这里:
最后的答案一定是从 O 出发,经过若干条边的反射到了一个顶点,
然后再从顶点经过若干条边到另一个顶点,最后再回到原点。
f[i][j]表示i这个点和j这个点经过光路最速原理走过去的值是多少。
这是两个点之间仅通过边反射的最短距离。
然后我们再用floyd求出任意两个点之间的最短路。
预处理另外两个数组,一个是从原点出发,顺时针反射到某个点的距离,
另一个是从原点出发逆时针反射到某个点的距离,这样线性扫一遍就行了。

计算几何和图论的结合,真好玩啊。
然后我顺便找到了原题,是2012ACM-ICPC-WF的H

WC2007疯狂赛车,也是这样一种题目。

然后继续讲课了

NOI2007货币兑换——分治好题233
有两种操作, n 天进行货币买卖,第i天可以进行两种操作。
1.花费s,按照市值 ai,bi 收获两种股票,两种股票的比例是固定的r_i
2.给定一个比例k,按照市值 ai,bi 把手中 k 的持有的 A B卖掉。
给定所有参数问底 n 天后最大持有现金数。
一个很显然的结论是每次都会操作所有的现金/股票
f[i]表示第i天最多有多少钱。
那么我们枚举上一个买入交易日j,第j天花所有钱买入股票,在第i天全部卖掉。
f[i]=maxf[i1],fa(j)a[i]+fb(j)b[j]
fb[j]=f[j]a[j]r[j]+b[j]
fa[j]=a[j]f[j]a[j]r[j]+b[j]
对于i,决策j优于k的条件是:
r[j]f[j]r[k]f[k]f[j]f[k]>b[i]a[i]

但是这个斜率优化的单调性十分的差,我们动态维护这个凸包很难。
平衡树是可以的。但我们考虑更简单的做法(也许吧,我是这么认为的)

其实,我们接下来需要干什么?
1.加点,维护上凸壳
2.用一条固定斜率的线从上往下扫描,回答碰到的第一个点
其中第二个问题等价于在凸包上二分。

考虑CDQ分治,我们先计算出左半边点的dp值,
考虑左半边的dp怎么影响右半边?
——左半边的点可能被右半边的询问线碰到。
操作变成:
给定左半边的点集,构造凸包;
给定左半边的凸包,二分右半边的斜率在左半边的位置。

这题的主要思想是利用CDQ将一些动态的东西转化为静态的。

这样做是 O(nlog2n)
考虑进一步优化。
我们比较容易想到的是二分的优化,将右半边的询问斜率进行排序。
然后我们二分后的斜率选择的点就是单调往右的。
再考虑第二步优化,因为我们已经分治了,不妨将下一层的凸包也传上来。
凸包的合并是可以做到 O(n) 用两个指针单调扫的。
这样复杂度就被优化到了 O(nlogn)

这道题的思想是十分重要的,回去一定要好好写一次。
练习题:WF2011,Machine Works

POI2011:METEOR
m 个天文台排成一个环形,每个天文台属于n个国家中的一个。
k 场流星雨,第i场波及 [l[i],r[i]] ,为每个天文台提供 ai 的陨石
每个国家有陨石需求量 bj 。问每个国家在第几场流星雨后达到陨石需求。

这道题在当初讲整体二分的时候做了0.0
线段树可以维护流星雨的信息,但是怎么统计呢?
我们可以用整体二分233,就是对答案进行分治。
每次询问加上 [L,M] 这段区间的流星,有多少国家满足了。
满足的二分左侧区间,不满足的二分右侧区间。
右侧区间信息怎么维护呢?我们可以用主席树/撤销操作/简单统计。

BZOJ3110 K大数查询
n 个vector:vi排成一排,维护以下操作:
1abci[a,b],vi.push _ back(c)
2abcUi[a,b]vic
第二个操作就是合并 [a,b] 这些区间后的第c大。
这也是经典题目啊,数据结构题QvQ,但哦我们还是要整体二分做!
我们对答案“分治”。那么每次要求的就是对于每一个询问 a,bans
扫描所有操作,每次询问是否存在至少 C 个数,他们<M(二分的 M )且在[a,b]区间范围内
查询就是查询一段树是不是大于 C

总结一下
分治是一个很有趣的东西,
绝大多部分题,尤其是CDQ分治和整体二分,
将动态的问题变成了一些静态的东西。

最后听说是一道娱乐题:K近邻相交查询
给定n个排序的实数,有若干组询问:
(x,y,k) ,询问距离x最近的k个点和距离y最近的k个点是否有交集
假定对于每个点没有两个点和它距离相同。
n,k<=105,ai<=109

又是rqy讲的qwq
显然距离每个点前k近的点是一段连续的区间。
二分距离x第k近的点距离是多少,然后我们再二分一次,距离x不超过v的点距离是多少。
这个做法是 O(nlog2n)

二分以每个点为中心往外扩 k 个,那么显然我们要看看x左延和右延的哪边距离大
balabala
这个做法是O(nlogn)

然后还可以拓展下,变成二维询问曼哈顿距离的K近邻相交查询

做法是一样的。
但是我们可以考虑旋转45度233
对于每个询问我们就可以转化为旋转45度的矩形有没有交。

今天真的是很不爽啊
做题量太少的后果。
明天要开始学数学了,十分慌张QAQ

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值