HDU5324 cqd分治
HDU5324 cqd分治
标签(空格分隔): 未分类
给你两个长度相同数列,求第一个不上升,第二个不下降的最长子序列长度。
这里要求的子序列对第一个和第二个来说是相同的。即如果你在第一个序列里选了第i个,那么在第二个序列里也要选第i个。
首先我们考虑怎么解决只有一个序列的情况。
这就是最普通的最长不下降子序列。考虑\(O(nlogn)\)的做法。
首先仍然是DP,$f[i]=\max(f[j]+1) , j < i $ & $ a_j < a_i \(. 我们需要考虑怎么在\)logn\(时间内求出\)\max(f[j]+1)$.这很容易。对于i,我们建立一颗权值线段树,每次单点修改,求区间最大值即可。(可以用zkw)
那么我们考虑如何解决这个二维问题。首先DP方程还是这样。
\[f[i]=\max(f[j]+1) , j < i , a_j > a_i , b_j<b_i \]
问题在于如果我们想用\(log\)的复杂度维护这个\(\max(f[j]+1)\),我们就需要一个二维线段树,这是非常令人难过的。因为首先二维线段树不好写不好调,而且更关键的是很容易MLE(或者TLE?)。
那么这类二维数据结构问题都可以考虑使用cdq分治。
cdq分治的基本思想就是把所有询问离线统一计算,这样我们就可以在计算的时候进行分治。
其实多数情况下就是把所有位置上的答案都计算出来。
所以cqd分治的第一个条件就是允许离线。
以这道题为例,我们考虑计算所有的\(f[i]\).如果用\(gao(1,n)\)表示计算\(f[1]\)~\(f
\),那么\(gao(1,n)\)就可以分成\(gao(1,n/2) , gao(n/2+1,n)\),这样我们就可以分治了。
当然直接分治是不对的,因为一个\(f[i]\)是受到他之前所有的\(f[j]\)的影响的。这在\(gao(1,n/2)\)时没有问题,但是在\(gao(n/2+1)\)时就会少考虑前一半对这一半的贡献。
那么很好办,cqd分治和普通分治的主要区别就是我们可以在\(gao(1,n/2)\)之后用\(O(n)或者O(nlogn)\)时间把前一半已经计算出来的\(f\)值对后一半的影响加进去。这样总体复杂度就是\(O(nlogn)\)或者\(O(nlog^2n)\)。具体复杂度取决于合并时的复杂度。
注意这里有cdq分治成立的第二个条件,那就是前一半对后一半的贡献是可以独立计算的,而且后一半不会影响前一半。否则没办法合并。
对于这道题而言,我们\(gao(1,n)\)的时候,先计算前一半,然后把前一半和后一半的数分别排序,对于后一半每个数,把前一半里比它小的插入线段树中,然后查询权值线段树中的最大值即可。合并复杂度\(O(nlogn)\),总体复杂度\(O(nlog^2n)\),和二维线段树一样,但是好写多了。
另外这道题要求答案字典序最小,那么DP的时候倒序做就可以了。(想一想就懂了)
实际上cdq分治就是在一个维度上改变了求解问题的顺序,从而避免了对整体使用二维数据结构。
转载于:https://www.cnblogs.com/loveidea/p/4701371.html
- HDU5324 cqd分治
- CQD(陈丹琦)分治 & 整体二分——专题小结
- CodeForces990G:GCD Counting(树分治+GCD)
- CF960G Bandit Blues 【第一类斯特林数 + 分治NTT】
- 线段树分治总结(线段树分治,线段树,并查集,树的dfn序,二分图染色)
- BZOJ 3924: [Zjoi2015]幻想乡战略游戏(动态点分治)
- #41 最短路(分治+线性基)
- 纯C语言:分治假币问题源码分享
- 《面试算法 LeetCode 刷题班》——4. 递归,回溯,分治
- [HDU4918]点分治+树状数组
- C - Painting Fence CodeForces - 448C(dp或分治)
- 点分治复习笔记
- 分治FFT学习笔记
- 五种常用算法之二:分治算法
- 【BJOI2017】树的难题【点分治】【线段树】
- POJ1741 Tree(点分治)
- Strassen矩阵乘法(分治策略,java语言实现)
- 棋盘覆盖问题(分治)(C语言)
- 求二维平面最近点对算法; 分治思想; 递归写的好精准,模仿ACM模板写的.;很多细节处理的很漂亮;
- 递归与分治策略(3)