随笔分类 - OI || algorithm
摘要:学了高数之后,以前一直理解得模模糊糊的时间复杂度明白了不少。 我们通常说的时间复杂度指的是大O,中文名称是渐进时间复杂度,为什么叫渐进时间复杂度, 原因就是其描述的是算法的耗时随着数据规模的变动的变化趋势。 所谓变化趋势,大约可以类比为导数。但是又有些不一样, 我们的大O在计算的时候并不需要把系数带
阅读全文
摘要:经过漫长(并不务正业)的暑假,我终于回归了OI。 下面以此代码为例子:Luogu4910 #include <cstdio> #include <cstring> typedef long long ll; const ll MOD = 1000000007; ll fbi[5][5] = {{1,
阅读全文
摘要:不必多说。 #include <cstdio> #include <cstring> int read(){ int x = 0,f = 1; char c = getchar(); while(c < '0' || c > '9') { if(c == '-') f = -1; c = getch
阅读全文
摘要:╭(′▽`)╯ 总之,我们都知道lca是啥,不需要任何基础也能想出来怎么用最暴力的方法求LCA,也就是深度深的点先跳到深度浅的点的同一深度,然后一起向上一步步跳。这样显然太慢了! 所以我们要用倍增,倍增比较屌,直接2^k速度往上跳,而且复杂度和树剖lca差不多,那么步骤分为两步 1.让两个点到同一深
阅读全文
摘要:拓扑排序 首先要求图为DAG 算法:首先将度为1的节点加入队列每次取出队首点u,在图中删去和u相邻的边继续将度数为1的点加入队列 到了最后, 如果没有度数为1的点,则图不是DAG 通过拓扑排序可以给DAG中的节点编号,也可以用来判断DAG 由于DAG有严格的顺序,不存在从后向前连接的边,所以可以做d
阅读全文
摘要:一、不定方程 要求逆元,首先要知道什么是不定方程。 已知a,b,c,求解x,y,形如ax + by = c 的方程就是不定方程。 不定方程有两种解的情况: 1.无解 2.存在且有无限的解 那么,如何判断解的情况呢? 这时候,只需要拿出gcd就可以了, 若gcd(a,b) | c,则方程存在解,为什么
阅读全文
摘要:我恨数论 因为打这篇的时候以为a|b是a是b的倍数,但是懒得改了,索性定义 a|b 为 a是b的倍数 咳咳,那么进入正题,如何证明gcd,也就是 gcd(a,b) = gcd(b,a%b)? 首先,设 p = a/b,c = a mod b 则a = p*b + c m = gcd(a,b),n =
阅读全文
摘要:操作数,一般用来做那些对数列进行添加、撤销操作的题。 假设一开始有一个空数列,有三个操作 (1)在数列后加一个数 (2)求数列中某位置的值 (3)撤销掉最后进行的若干次操作(1和3) 考虑建一棵树,1操作则为在当前节点下新加一个节点,2操作求数列k位置值,则为从根节点到当前节点k个节点的位置的节点
阅读全文
摘要:所谓二分图,是可以分为两个点集的图; 所谓二分图最大匹配,是两个点集之间,每两个不同点集的点连接,每个点只能连一个点,最大的连接数就是最大匹配。 如何解最大匹配,需要用到匈牙利算法。 另:本文写了很多细节,有的地方比较啰嗦,请大佬放过 匈牙利算法是一个递归的过程,它的特点,我觉得可以归为一个字:“让
阅读全文
摘要:一、基础操作 1.a<<b 将二进制a左移b位,不够的地方用0补位 例如 100<<2 == 10000 2.a>>b 将二进制a右移b位 例如 100>>2 == 1 3.a|b 或操作(按位或),相同位中只要有一个1或者两个1则结果为1,全0则结果为0 4.a&b 与操作(按位与),相同位中只要
阅读全文
摘要:快速幂:因为a+b=c => n^a * n^b = n^c 所以n^m可以分解为n^m=n^a1 * n^a2 * n^a3... * n^ak ,a1+a2+a3...+ak=m 所以我们想到,如果存在k<m,并且可以以O(k)的复杂度求出n^a1、n^a2、n^a3...n^ak中的每一个数,
阅读全文
摘要:如何查找一个范围内的所有素数? 可以是从1~n挨个判断n%i 是否 == 0,也可以从 1~sqr(n) 一个个判断。 相信你们也听说过埃氏筛法,是使用每一个数的倍数筛掉合数!但是!每一个合数要被筛多次!这就给了我们优化的可乘之机! 它叫做线性筛,顾名思义,时间复杂度是线性的。 我们都知道,线性的复
阅读全文
摘要:对于线段树,我们一般需要n*4的空间去存储线段树,然后有一种玄学操作是用指针来实现线段树。 #include <inttypes.h> #include <algorithm> #include <cstdio> #include <iostream> #include <vector> #defi
阅读全文
摘要:所谓单调队列,就是一个保持着某种性质的队列,通常是队列从队头到队尾,维护一种递增递减的关系。 这种队列通常用来解决一些连续区间的最值问题。 这种队列的入队要保证符合当前的性质,例如一个递增的单调序列(从左到右是从头到尾):7,9,10,11 这时,入队时要保证是递增的:例如12这个元素可以入队,而1
阅读全文
摘要:斯特林数分为第一类斯特林数:S1(n,k)和第二类斯特林数:S2(n,k)。 S1(n,k)代表在n个元素中选出k个环的方案数,S2(n,k)代表在n个元素中选出k个非空集合的方案数, 不同之处在于,在第一类斯特林数中我们在意这些环的顺序,在第二类斯特林数中我们不在意顺序,但在意集合中装了什么(感觉
阅读全文
摘要:对拍的方法是先用生成器生成几组随机数据,然后用暴力算法和当前算法对比结果来确保正确性。 数据生成器: 引入cstdlib与ctime两个库,然后通过srand初始化随机数: 然后,用rand()获得随机数。 为了确保随机性,这里对得到的随机数进行了处理。 为了在 1~i 的范围内生成随机数,使用 r
阅读全文
摘要:昨天晚上看蓝书,看到了LIS问题的优化解法。 是比O(n方)更快的解法,实际上是一个常数优化。 先讲一下朴素的解法: 一个集合a,a[i]是第i个元素。设dp[i]为以编号为i的元素结尾的最长不上升子序列。 找到状态转移: dp[i] = max{dp[j]}+1 (j < i && a[j] >=
阅读全文
摘要:介绍下简单的分块: 当我们遇到区间类问题的时候,如何保证我们快速而高效地完成操作? 答案是线段树分块。 所谓分块,就是把一个序列分成许多块分别维护。是不是想起了树状数组 这样能大大提高效率: 例如,我们需要查询l,r中所有元素的和 利用分块,我们可以把1 2 3 4 5 6 7 8 9 10 分为
阅读全文
摘要:Kruskal是有关于最小生成树的算法。 这个算法非常好理解,用一句话来概括就是: 从小到大找不同集合的边。 那么,具体是怎样的呢。 1.先把所有顶点初始化为一个连通分量。 2.从所有边中选择最小的(指权值)边,判断该边是否已经在当前构造的连通分量中,如果是,则放弃这条边,找下一条边。 3.重复第二
阅读全文
摘要:何为向量? 在初中课本中,我们知道: 这样解释太笼统了,现在我们只讨论平面上的向量。 那么,我们约定:在平面上的向量,由一个二元组组成:如α(c1,c2)。 在此平面上建立一个平面直角坐标系,设向量两端点分别为:x1(a1,b1), x2(a2,b2)。 那么,c1 = a2 - a1, c2 =
阅读全文