【学习笔记】杂项
对于本版块:会把不好放进其他模块的独立算法放进来。
cdq 分治
我们考虑二维偏序是怎么处理的。显然我们对第一维排序然后对第二维开树状数组统计。
同样我们尝试把第一维排序,然后尝试进行分治。将当前分治段分成左右两部分,并把这两部分分别处理好。
inline bool cmp1(Node c1,Node c2){
return ((c1.x^c2.x)?c1.x<c2.x:((c1.y^c2.y)?c1.y<c2.y:c1.z<c2.z));
}//第一次排序
我们显然能够发现在分治的小区间处理好后,在当前范围内左区间不会被更改,但是这种结论在有三元组完全相等时无效,所以我们把三元组去重。
然后我们发现左右区间都处理完答案后第一维不重要了,因为我们只用知道 在现在这个区间只剩左区间对右区间的贡献没有被统计了。
然后是不是变成了二维数点。我们类似归并的做法把左右端点排个序。把左右区间按第二维排个序。
inline bool cmp2(Node c1,Node c2){
return ((c1.y^c2.y)?c1.y<c2.y:c1.z<c2.z);
}//第二次排序
按照第二维,对左区间加进一个树状数组中,对右区间查询第三维。
注意退出的时候清空树状数组。
考虑把分治的二叉树表示出来,每次都遍历每一整层,每一层长度都是 \(n\),遍历一个长度为 \(l\) 的区间因为带排序和树状数组是 \(O(l\log l)\) 的,所以遍历一层大约是 \(O(n\log n)\),一共是 \(\log n\) 层,所以总复杂度是 \(O(n\log^2 n)\)。
四维偏序,考虑 cdq 套 cdq 优化 dp。
外面套 cdq 的那一层为了传到里面给每个点设一个 \(lf\) 代表这个点在外套的 cdq 里面是不是给贡献的点,然后就是普通 cdq 了。
因为是优化 dp,所以 cdq 的顺序是左中右,也就是先 cdq 左边,然后处理这一层的数据,然后 cdq 右边。
因为先处理这一层的数据然后再搞右边,为了使右边仍然有序,要新开一个数组搞。
整体二分
适用于有多次询问,每次询问都可以二分,二分过程都相似。此时我们可以考虑把这些询问一起处理。
具体地,定义函数 solve(al,ar,l,r)
表示现在答案值域在 \([al,ar]\) 之间,答案在这个值域内的问题区间是 \([l,r]\),那么我们可以发现这个东西要求问题答案连续,所以我们在函数内进行问题的归并。
每次进行函数的时候,因为是二分所以要搞一个 mid 来进行新的转移,然后检查 \([l,mid]\) 可能是哪些问题的答案然后把这两个问题划分传到下一层。
普通二分的终点是答案值域只剩一个数,在这里体现为 \(al=ar\),那么答案在这个值域的区间答案都是 \(al\)。
复杂度 \(O(n\log n)\),乘上一个检查答案的复杂度。
挂一个 离线动态区间 k 小值,只要不是强制在线就可以放心写整体二分,复杂度和树套树一样是 \(log^2\) 的。
反悔贪心
对于部分假贪心的题目,若所有选择带来的消耗一样,那么我们能够处理出来当前选择的东西里面价值最小的那一个,当没有空位选择下一个东西的时候,我们就能够把这个价值最小的物品和当前想要加进来的东西作比较然后扔掉一个。
因为涉及到加入和时刻查询最小价值,所以考虑堆来维护。
01 分数规划
每个物品有两个属性 \(a,b\),让你选一些数得到 \(\max/\min\frac{\sum a}{\sum b}\)。
首先这个东西具有单调性,这个很显然。所以可以考虑二分这个比值是否 \(\ge mid\)。
拆一下式子就是问能不能有 \(\sum(a-mid\times b)\ge0\)。发现答案变得只跟每个单独物品有关,按照题目要求搞就行。
对于边界的判断,在第二属性为物品个数,即比值为平均值时边界取权值最大最小值。其他情况不知道。
康托展开
对于一个排列 \({p_n}\) ,求他在 \(n\) 的全排列中的排名。
\(ans=1+\sum_{i=1}^{n}\sum_{j=i+1}^{n}[a_j<a_i]\times(n-i)!\)。即我们按字典序看当前一位会产生多少个排名更小的排列。相当于在后面选填在这一位能够比当前排名大的数。