前言
这篇 blogblogblog 仅仅记录一下之前学的一些比较简单的东西,为了防止忘记。所以有不详细的地方请谅解QAQ。
拉格朗日插值
给出平面上的 n+1n+1n+1 个点 (xi,yi)(0≤i≤n)(x_i,y_i)(0\leq i\leq n)(xi,yi)(0≤i≤n),找到一个 nnn 次多项式 f(x)f(x)f(x),使得这个多项式过这 n+1n+1n+1 个点,给出一个 kkk,求 f(k)f(k)f(k)。 n≤5000n\leq 5000n≤5000。
天才滴拉格朗日构造出了这个多项式(这里就不细究是怎么构造出来的了>_<):
f(k)=∑y=0nyi∏i≠jk−xjxi−xjf(k)=\sum\limits_{y=0}^{n}y_i\prod\limits_{i\neq j}\dfrac{k-x_j}{x_i-x_j}f(k)=y=0∑nyii=j∏xi−xjk−xj
容易验证 yi=f(xi)y_i=f(x_i)yi=f(xi)(读者自证不难,而且 f(x)f(x)f(x) 是关于 xxx 的 nnn 次多项式。
于是我们可以在 O(n2)O(n^2)O(n2) 复杂度完成插值。如果预处理出 ∏i≠j1xi−xj\prod\limits_{i\neq j}\dfrac{1}{x_i-x_j}i=j∏xi−xj1,就可以 O(n)O(n)O(n) 完成插值!
拉格朗日插值的一个应用
求 1k+2k+...+nk1^k+2^k+...+n^k1k+2k+...+nk。其中,n≤1015,k≤107n\leq 10^{15},k\leq 10^7n≤1015,k≤107。
组队赛出了这个我居然不会,太丢人了…
由小学知识,自然数 kkk 次幂的前缀和是一个 k+1k+1k+1 次多项式,于是可以通过前 k+2k+2k+2 个点插出这个多项式。
问题在于,怎么 O(k)O(k)O(k) 求 f(x)=∑y=0nyi∏i≠jx−xjxi−xjf(x)=\sum\limits_{y=0}^{n}y_i\prod\limits_{i\neq j}\dfrac{x-x_j}{x_i-x_j}f(x)=y=0∑nyii=j∏xi−xjx−xj。
事实上,由于 xxx 坐标是连续的,我们可以将原式写成:
f(x)=∑y=0nyi∏i≠jx−ji−jf(x)=\sum\limits_{y=0}^{n}y_i\prod\limits_{i\neq j}\dfrac{x-j}{i-j}f(x)=y=0∑nyii=j∏i−jx−j
然后呢,我们考虑优化连乘部分。
上面的 ∏i≠jx−j\prod\limits_{i\neq j}x-ji=j∏x−j,可以写成 ∏j=0k+1x−jx−i\dfrac{\prod\limits_{j=0}^{k+1}x-j}{x-i}x−ij=0∏k+1x−j,于是可以预处理。
下面的 ∏i≠ji−j\prod\limits_{i\neq j}i-ji=j∏i−j,我们拆成两部分,变成 (∏j=0i−1(i−j))×(∏j=i+1k+1(i−j))(\prod\limits_{j=0}^{i-1}(i-j))\times(\prod\limits_{j=i+1}^{k+1}(i-j))(j=0∏i−1(i−j))×(j=i+1∏k+1(i−j)),前面那部分就是 i!i!i!(这里是阶乘的意思,不是感叹号!),后面那部分就是 (−1)k−i+1(k−i+1)!(-1)^{k-i+1}(k-i+1)!(−1)k−i+1(k−i+1)!。
于是预处理阶乘和阶乘的逆,就可以实现 O(k)O(k)O(k) 插值了!
点分治
点分治算法算是分治思想在树上的一个重大应用,不过其只能用于无根树QAQ。
点分治一般解决的是树上的路径问题。我们考虑当前的一棵子树,那么路径可以分为两种,一种是经过根节点的,一种是在他的子树中的。
第二种可以递归解决,如果可以在 O(子树大小)O(子树大小)O(子树大小) 的复杂度求出第一种的路径,那么我们就可以在 O(nlogn)O(nlogn)O(nlogn) 总复杂度求解这个问题。(这里我讲的很不详细,建议读者自行做题理解>_<)
具体做法是每次求出子树的重心,以子树的重心为根解决子问题(由于这棵树是无根树,所以这种做法是可行的),不难证明,最多只会递归 lognlognlogn 层。
复杂度是 O(nlogn)O(nlogn)O(nlogn) 的,详情可以参考主定理。
不过呢,我们可以考虑一种极端情况,就是满二叉树的情况。那么 T(n)=2T(n2)+nT(n)=2T(\dfrac{n}{2})+nT(n)=2T(2n)+n,可以看出复杂度是 O(nlogn)O(nlogn)O(nlogn) 的。
可并堆
什么?你以为我要讲左偏树?那是不可能滴!因为我还没学
这里介绍的是一种黑科技,就是 pbdspb_dspbds 库里面的配对堆,其用法非常简单,而且效率和左偏树差不多(稍慢一点)。
用法大概就是:
#include <ext/pb_ds/priority_queue.hpp>
using namespace __gnu_pbds;
typedef __gnu_pbds::priority_queue<int, greater<int>, pairing_heap_tag> Heap;
常用操作:
push() //会返回一个迭代器
top() //同 stl
size() //同 stl
empty() //同 stl
clear() //同 stl
pop() //同 stl
join(priority_queue &other) //合并两个堆,other会被清空
split(Pred prd,priority_queue &other) //分离出两个堆
modify(point_iterator it,const key) //修改一个节点的值
一般左偏树能做的题都能用这个来做,除了部分需要可持久化的题目。
线段树合并
咕咕咕
89

被折叠的 条评论
为什么被折叠?



