算法打怪升级之路
文章平均质量分 51
阳光.
这个作者很懒,什么都没留下…
展开
-
区间DP问题
例如有 4 堆石子分别为 1 3 5 2, 我们可以先合并 1、2 堆,代价为 4 ,得到 4 5 2, 又合并 1,2 堆,代价为 9 ,得到 9 2 ,再合并得到 11 ,总代价为 4+9+11=24;每次只能合并相邻的两堆,合并的代价为这两堆石子的质量之和,合并后与这两堆石子相邻的石子将和新堆相邻,合并时由于选择的顺序不同,合并的总代价也不相同。如果第二步是先合并 2,3 堆,则代价为 7 ,得到 4 7,最后一次合并代价为 11 ,总代价为 4+7+11=22。原创 2022-09-02 13:28:09 · 73 阅读 · 0 评论 -
线性DP问题
和“只出现j,没出现i”“只出现i,没出现j”的概念是不同的,但因为前两者包括后两者,所以可以通过求前两者的最大值求出整体的最大值(上面ABC的例子)给定两个长度分别为 N 和 M 的字符串 A 和 B ,求既是 A 的子序列又是 B 的子序列的字符串长度最长是多少。那么求集合C中的最大值,只需先求集合A的最大值,再求集合B的最大值,最后再把两个最大值比较,最后求出的最大值就是C的最大值。给定一个长度为 N 的数列,求数值严格单调递增的子序列的长度最长是多少。原创 2022-09-02 11:47:52 · 209 阅读 · 0 评论 -
分组背包问题
如果要用到上一层的状态的话,就要从大到小,反之从小到大。关键是用二维数组表示,其余和01背包差别不大。原创 2022-08-31 11:02:54 · 78 阅读 · 0 评论 -
多重背包问题
这种朴素算法在数据量大时会超时,所以我们需要优化。可以看出,朴素版本的多重背包和完全背包是类似的。个,拆完后再对所有新出来的物品分别作01背包。减一项求最大值),所以不能用这种方式来优化。可以再加一项求最大值,不能用已知。已知,上面的未知,但下面的。...原创 2022-08-31 10:19:44 · 103 阅读 · 0 评论 -
完全背包问题
你会发现完全背包是从i开始转移的,所以也就不用像01背包那样把j从大到小循环。我们发现,上面的算式只比下面的算式多了一个。回忆完全背包和01背包的状态转移方程。从状态表示、状态计算两方面考虑。种物品,且总体积不大于。个物品选几个的若干子集。,因此,我们可以得出。...原创 2022-08-30 15:16:59 · 102 阅读 · 0 评论 -
01背包问题
以上代码是二维版,但实际上,我们可以把dp数组优化成一维的。的循环变为从大到小,这样数组就是没更新过的,也就变相等于。注意含i的情况:必须满足j>=vi才行,不然会超重。注意i的含义:指只选取前i个物品。,这部分怎么表示呢?,而j那维的数组都小于等于。时无意义,因为代码有。...原创 2022-08-30 12:43:24 · 547 阅读 · 0 评论 -
欧几里得算法、扩展欧几里得算法、求逆元、中国剩余定理、扩展中国剩余定理
欧几里得算法求两个正整数 a 和 b 的 最大公约数 d则有 gcd(a,b) = gcd(b,a%b)证明:设a%b = a - kb 其中k = a/b(向下取整)若d是(a,b)的公约数 则知 d|a 且 d|b 则易知 d|a-kb 故d也是(b,a%b) 的公约数若d是(b,a%b)的公约数 则知 d|b 且 d|a-kb 则 d|a-kb+k*b = d|a 故而d|b 故而 d也是(a,b)的公约数因此(a,b)的公约数集合和(b,a%b)的公约数集合相同 所以他们的最大公约数也原创 2021-12-18 12:29:36 · 431 阅读 · 0 评论 -
欧拉函数、欧拉定理、费马小定理(附例题)
欧拉函数欧拉函数的两种求法:ACWING873欧拉函数给定 n 个正整数 ai ,请你求出每个数的欧拉函数。欧拉函数的定义输入格式第一行包含整数 n 。接下来 n 行,每行包含一个正整数 ai 。输出格式输出共 n 行,每行输出一个正整数 ai 的欧拉函数。数据范围1≤n≤100 ,1≤ai≤2×109输入样例:3368输出样例:224AC代码:#include <bits/stdc++.h>using namespac原创 2021-12-15 12:54:29 · 1589 阅读 · 0 评论 -
约数(附例题)
int范围内的整数,约数个数最多的大概是1500个n内所有数的约数的个数=n内所有数倍数的个数=nlogn,平均下来每个数的约数的个数就是lognACWING869 试除法求约数题目描述:给定n个正整数ai,对于每个整数ai,请你按照从小到大的顺序输出它的所有约数。输入格式第一行包含整数n。接下来n行,每行包含一个整数ai。输出格式输出共n行,其中第 i 行输出第 i 个整数ai的所有约数。数据范围1≤n≤100,2≤ai≤2∗10^9输入样例:268输出样例:1 2 3原创 2021-12-13 15:48:05 · 2310 阅读 · 1 评论 -
快速幂(附例题)
快速幂求a^b%p。暴力做法是直接模拟,但是由于a和b的规模都达到了1e9,所以算a^b时会爆,用long long也不行。第一步优化:利用取模运算法则:(a + b) % p = (a % p + b % p) % p (1)(a - b) % p = (a % p - b % p ) % p (2)(a * b) % p = (a % p * b % p) % p (3)观察第三条法则,我们可以借助这个法则对每一步都提前进行取模运算,这样就不会爆了。上述优化固然不会爆,但是算法时间原创 2021-12-12 13:06:01 · 836 阅读 · 0 评论 -
由数据范围反推算法时间复杂度和需要用到的算法类型
一般ACM或者笔试题的时间限制是1秒或2秒。在这种情况下,C++代码中的操作次数控制在 107∼108107∼108 为最佳。下面给出在不同数据范围下,代码的时间复杂度和算法该如何选择:n≤30n≤30, 指数级别, dfs+剪枝,状态压缩dpn≤100n≤100 => O(n3)O(n3),floyd,dp,高斯消元n≤1000n≤1000 => O(n2)O(n2),O(n2logn)O(n2logn),dp,二分,朴素版Dijkstra、朴素版Prim、Bellman-Ford原创 2021-12-10 19:46:48 · 156 阅读 · 0 评论 -
朴素筛法、埃氏筛法、线性筛法(附例题)
朴素筛法和埃氏筛法朴素筛法时间复杂度为O(nlogn)埃氏筛法优化后,时间复杂度为O(nloglogn),和O(n)几乎持平例题给定一个正整数 n ,请你求出 1∼n 中质数的个数。输入格式共一行,包含整数 n 。输出格式共一行,包含一个整数,表示 1∼n 中质数的个数。数据范围1≤n≤106输入样例:8输出样例:4朴素筛法思想:从2开始枚举到n,如果是素数就让计数器加1,并且用当前的数i筛掉所有当前数i的倍数(比如2的倍数4,8,12…都筛掉,因为他们肯原创 2021-12-09 16:50:07 · 971 阅读 · 0 评论 -
试除法判定质数、试除法分解质因数(附例题)
试除法判定质数无论在何种情况下,时间复杂度都是O(sqrt(n))acwing.866.试除法判断质数试除法判断质数给定n个正整数ai,判定每个数是否是质数。输入格式第一行包含整数n。接下来n行,每行包含一个正整数ai。输出格式共n行,其中第 i 行输出第 i 个正整数ai是否为质数,是则输出“Yes”,否则输出“No”。数据范围1 ≤ n ≤ 100,1 ≤ ai ≤ 231−1输入样例:226输出样例:YesNo试除法分解质因数n中最多只包含一个大于s原创 2021-12-09 16:29:03 · 295 阅读 · 0 评论 -
最小生成树:朴素版prim、kruskal(附例题)
最小生成树设G是无向图。子图:K是G的子图,则K的顶点和边都包含于G。生成子图:若K是G的子图,且K包含G的所有顶点,则K是G的生成子图。生成树:若T是树,且T是G的生成子图,则T是G的生成树。最小生成树:若G是带权的,且T是G的生成树里边的权值累加最小的生成树,那么称T是G的最小生成树。朴素版prim适用于稀疏图(顶点数的平方小于等于边数)和Dijkstra算法思想有点相似,但区别是Dijkstra每次更新的是到源点的距离,而Prim每次更新的是到集合的最短距离。Prim可以处理带负权原创 2021-12-06 10:48:42 · 1061 阅读 · 0 评论 -
最小生成树、二分图问题概述
最小生成树:要在各个城市之间修路,每个城市只走一遍,问最小费用是多少。最小生成树针对的是无向图prim朴素版prim解决稠密图问题,只要记住朴素版就可以了,堆优化版不如kruskalkruskal解决稀疏图问题,最大开销来自排序二分图一般通过染色法来判别一个图是不是二分图匈牙利算法寻求最大匹配,即可以把二分图的两个集合看成男嘉宾和女嘉宾,男嘉宾主要匹配女嘉宾的过程。注意关键思路:给别的男的戴绿帽子(如果一个男A只看上了女B,而女B已经和男B配对,但男B还有备胎女C,那么就和男B商量一下,.原创 2021-12-04 10:10:56 · 130 阅读 · 0 评论 -
Floyd算法(附例题)
ps:算法题调代码的两个方法:cout法和删代码法Floyd算法采用动态规划思想,只要用三个循环就可以了,实现简单。k必须在最外层,i和j的顺序随意。d[i][j] = min(d[i][j], d[i][k] + d[k][j]);是核心代码。Floyd算法可以用来解决多源汇最短路问题,而且可以处理带负权边的多源汇最短路问题,但无法处理带负权回路的最短路问题。AcWing 854. Floyd求最短路给定一个n个点m条边的有向图,图中可能存在重边和自环,边权可能为负数。再给定k个询问,原创 2021-12-02 12:50:34 · 939 阅读 · 0 评论 -
Bellman-ford算法、SPFA算法、SPFA判断负环(附例题)
Bellman-ford算法用来解决Dijkstra算法无法求带负权的最短路问题效率较低,代码实现简单可以解决限制边数、带负权的最短路问题,并且不怕负环ACWING853. 有边数限制的最短路给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环, 边权可能为负数。请你求出从 1 号点到 n 号点的最多经过 k 条边的最短距离,如果无法从 1 号点走到 n 号点,输出 impossible。注意:图中可能 存在负权回路 。输入格式第一行包含三个整数 n,m,k。接下来 m 行,原创 2021-12-01 17:35:19 · 263 阅读 · 0 评论 -
Dijkstra算法(朴素,堆优化)+例题
Dijkstra算法基于贪心,分为朴素版和堆优化版,稠密图用朴素版,稀疏图用堆优化版。算法思想首先给定起始点和终点,求起始点到终点的最短路径。Dijkstra算法的做法是:在所有顶点里找到距离起点最近的点,将它放入集合S。用这个顶点来更新其它顶点到起点的距离。重复1,2步,直到所有顶点都在集合S里,此时,终点存的距离就是终点到起点的最短距离。朴素版Dijkstra例题ACWING849. Dijkstra求最短路 I给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环,所有边权原创 2021-11-27 13:56:43 · 1733 阅读 · 0 评论 -
最短路问题概述
分类1.单元最短路求一个点到其它所有点的最短距离所有边权都是正数的图(朴素Dijkstra算法 O(n^2)、堆优化Dijkstra算法O(mlogn),n表示点,m表示边)存在负权边(Bellman-Ford O(nm),SPFA O(m),最坏O(nm))2.多源汇最短路任选两个点,从其中一个点走到另外一个点的最短距离只有Floyd算法,O(n^3)应用场景只有正权,是稠密图:朴素Dijkstra只有正权,是稀疏图:堆优化Dijkstra负权边:SPFA多源汇:Floyd原创 2021-11-24 10:09:04 · 798 阅读 · 0 评论 -
拓扑排序(附例题)
ACWING848 拓扑排序给定一个 n nn 个点 m mm 条边的有向图,点的编号是 1 11 到 n nn,图中可能存在重边和自环。请输出任意一个该有向图的拓扑序列,如果拓扑序列不存在,则输出 − 1 -1−1。若一个由图中所有点构成的序列 A AA 满足:对于图中的每条边 ( x , y ) (x, y)(x,y),x xx 在 A AA 中都出现在 y yy 之前,则称 A AA 是该图的一个拓扑序列。输入格式第一行包含两个整数 n nn 和 m mm。接下来 m mm 行,每行包含两原创 2021-11-23 16:45:18 · 2080 阅读 · 0 评论 -
BFS(广度优先搜素,附例题)
AcWing 844. 走迷宫给定一个n*m的二维整数数组,用来表示一个迷宫,数组中只包含0或1,其中0表示可以走的路,1表示不可通过的墙壁。最初,有一个人位于左上角(1, 1)处,已知该人每次可以向上、下、左、右任意一个方向移动一个位置。请问,该人从左上角移动至右下角(n, m)处,至少需要移动多少次。数据保证(1, 1)处和(n, m)处的数字为0,且一定至少存在一条通路。输入格式第一行包含两个整数n和m。接下来n行,每行包含m个整数(0或1),表示完整的二维数组迷宫。输出格式输出一个原创 2021-11-23 15:20:04 · 127 阅读 · 0 评论 -
图的深度优先遍历和广度优先遍历(附例题)
图的存储:邻接表、邻接矩阵(主要用邻接表)树也是一种特殊的图无向图可以表示为有向图的形式图的深度优先遍历和广度优先遍历:思想和深度优先搜索、广度优先搜索是一样的图的深度优先遍历例题:Acwing 846-树的重心题目:给定一颗树,树中包含 n 个结点(编号 1∼n)和 n−1 条无向边。请你找到树的重心,并输出将重心删除后,剩余各个连通块中点数的最大值。重心定义:重心是指树中的一个结点,如果将这个点删除后,剩余各个连通块中点数的最大值最小,那么这个节点被称为树的重心。输入格式第一行包含原创 2021-11-23 15:13:07 · 4202 阅读 · 0 评论 -
DFS(深度优先搜索,附例题)
ACWING842 排列数字题目描述给定一个整数n,将数字1~n排成一排,将会有很多种排列方法。现在,请你按照字典序将所有的排列方法输出。输入格式共一行,包含一个整数n。输出格式按字典序输出所有排列方案,每个方案占一行。数据范围1≤n≤7样例输入样例:3输出样例:1 2 31 3 22 1 32 3 13 1 23 2 1#include <bits/stdc++.h>using namespace std;int path[100], st[100]原创 2021-11-18 11:09:44 · 893 阅读 · 0 评论 -
在C/C++中使用输入输出流
比如我们想把输入输出的数据存到文件里,可以这样做:C语言下首先定义文件指针FILE *fin, *fout;fin = fopen("datain.txt", "r+");fout = fopen("dataout.txt", "w+");然后改变输入输出的函数:int a;fscanf(fin, "%d", &a);fprintf(fout, "%d", a);最后记得要关闭文件fclose(fin);fclose(fout);C++引入fstream头文件,然后原创 2021-11-17 15:47:03 · 481 阅读 · 0 评论 -
c++ stl讲解
大多数stl容器都有size()和empty()函数vector倍增思想操作系统有这样一个特性:申请空间所用的时间与申请空间的大小无关,与申请的次数有关。申请一次a[1000]要比申请1000次a[1]快1000倍。于是vector作为变长数组,采用的方法是:假如当前vector的容量为n,当申请的空间变大时,新创造一个2n的vector,然后把当前vector的元素copy过去。vector有一个黑科技:比较。比较按字典序规则来。pairpair适用于存储两种不同类型的变量,比如一个是int,原创 2021-11-14 19:23:39 · 387 阅读 · 0 评论 -
哈希表:一般哈希,字符串哈希(附例题)
存储结构1.开放寻址法(y总推荐)开到题目范围的2-3倍,开放寻址法原理类似于上厕所2.拉链法类似于邻接表字符串哈希方式哈希表常用操作算法里常考:添加,查找如果非要实现删除,也不是真正删掉这个点,而是开一个布尔变量标记哈希函数一般都直接取模,取模的数一般来说取质数,并且这个数要离2的整次幂尽可能远。可以证明,这样做引起冲突的概率最小。冲突拉链法:开一个一维数组,存储所有哈希值,在每一个槽上加一个链,用来存储这个槽上有的所有冲突的数。...原创 2021-11-13 12:06:17 · 348 阅读 · 0 评论 -
堆(基本介绍,代码实现,以及例题)
1.堆的功能1.插入一个数2.求集合当中最小值3.删除最小值(1-3stl能做)4.删除任意一个元素5.修改任意一个元素堆是一棵完全二叉树小根堆:每一个结点的值都小于等于 左右儿子2.堆的存储用数组存储,1号点是根节点,x的左儿子是2x,右儿子是2x+1下标从1开始比较方便ph中p是指针,h是堆3.堆的函数down(x),往下调整up(x),往上调整heap_swap,交换元素和映射...原创 2021-11-10 10:24:21 · 1414 阅读 · 0 评论 -
并查集(ACWING三道题)
1.适用题型在我个人理解,并查集是用于解决这样的问题:题目中的数据分多个集合,并且有合并的可能,有时需要查找两个元素是不是在同一集合,以及该集合中所有元素的数量。有时也需要通过两个元素在同一集合中的位置,来确定这两个元素之间的关系,2.并查集的核心函数朴素并查集:这种并查集只需要两个功能:合并和查找祖宗结点。需要的基本数据结构:p[N],用来存储每一个下标的父亲结点。查找函数 int find(int x) { if (p[x] != x) p[x] = find原创 2021-11-08 10:50:47 · 497 阅读 · 0 评论 -
Trie树讲解(例题:ACWING 835,ACWING 143)
Trie树又称为字典树,这个数据结构的意义是高效地存储和查询字符串。我们先来看一下它的思想。关于树的定义为了方便我们后面的理解,我先把后面会用到的一些名词介绍一下。(有时输入法会把结点和节点打错,故以下的“节点”如无特殊说明,都可看作是“结点”)孩子结点:一个结点的子树的根结点就是该结点的孩子结点。父亲结点:一个结点如果有孩子结点,那么它就是它的孩子结点的父亲结点。兄弟结点:与该结点同父亲的结点称为该结点的兄弟结点。堂兄弟结点:同一层次非同父亲的结点祖先节点和子孙结点:如果存在一条从结点X到原创 2021-11-03 11:24:59 · 181 阅读 · 0 评论 -
介绍KMP算法思想(例题:ACWING 831 kmp字符串)
题目描述给定一个模式串S,以及一个模板串P,所有字符串中只包含大小写英文字母以及阿拉伯数字。模板串P在模式串S中多次作为子串出现。求出模板串P在模式串S中所有出现的位置的起始下标。输入格式第一行输入整数N,表示字符串P的长度。第二行输入字符串P。第三行输入整数M,表示字符串S的长度。第四行输入字符串M。输出格式共一行,输出所有出现位置的起始下标(下标从0开始计数),整数之间用空格隔开。数据范围1≤N≤10^41≤M≤10^5输入样例:3aba5ababa输出样例:0原创 2021-11-02 12:08:42 · 137 阅读 · 0 评论 -
ACWING 154滑动窗口
#include <bits/stdc++.h>using namespace std;const int N=1e6+10;int a[N],q[N],hh=0,tt=-1;int main(){ ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n,k; cin>>n>>k; for(int i=0;i<n;i++) {原创 2021-11-02 08:48:05 · 123 阅读 · 0 评论 -
如何最大程度地提高cin和cout的效率
首先在主函数输入如下代码: ios::sync_with_stdio(false); cin.tie(); cout.tie();然后,尽量多用“\n”代替endl,只有在一些大程序需要刷新输出流时,再用endl。原创 2021-10-31 19:04:46 · 141 阅读 · 0 评论 -
ACWING830 单调栈
题目描述(acwing 830单调栈)给定一个长度为N的整数数列,输出每个数左边第一个比它小的数,如果不存在则输出-1。输入格式:第一行包含整数N,表示数列长度。第二行包含N个整数,表示整数数列。输出格式:共一行,包含N个整数,其中第i个数表示第i个数的左边第一个比它小的数,如果不存在则输出-1。数据范围:1≤N≤1e5 1≤数列中元素≤1e9输入53 4 2 7 5输出-1 3 -1 2 2代码#include <bits/stdc++.h>using name原创 2021-10-31 18:55:02 · 271 阅读 · 0 评论 -
ACWING828 模拟栈
题目描述实现一个栈,栈初始为空,支持四种操作:(1) “push x” – 向栈顶插入一个数x;(2) “pop” – 从栈顶弹出一个数;(3) “empty” – 判断栈是否为空;(4) “query” – 查询栈顶元素。现在要对栈进行M个操作,其中的每个操作3和操作4都要输出相应的结果。输入格式第一行包含整数M,表示操作次数。接下来M行,每行包含一个操作命令,操作命令为”push x”,”pop”,”empty”,”query”中的一种。输出格式对于每个”empty”和”query原创 2021-10-30 15:47:40 · 163 阅读 · 0 评论 -
ACwing 829 模拟队列
题目描述实现一个队列,队列初始为空,支持四种操作:(1) “push x” – 向队尾插入一个数x;(2) “pop” – 从队头弹出一个数;(3) “empty” – 判断队列是否为空;(4) “query” – 查询队头元素。现在要对队列进行M个操作,其中的每个操作3和操作4都要输出相应的结果。输入格式第一行包含整数M,表示操作次数。接下来M行,每行包含一个操作命令,操作命令为”push x”,”pop”,”empty”,”query”中的一种。输出格式对于每个”empty”和”q原创 2021-10-30 15:44:30 · 108 阅读 · 0 评论 -
ACWING827 双链表
#include <bits/stdc++.h>using namespace std;const int N = 100010;int e[N], l[N], r[N], idx;void init(){ r[0] = 1; l[1] = 0; idx = 2;}void add(int k, int x){ e[idx] = x; r[idx] = r[k]; l[idx] = k; l[r[k]] = idx;原创 2021-10-29 19:00:56 · 114 阅读 · 0 评论 -
2021-10-28 ACWING826 单链表
先上代码:#include <bits/stdc++.h>const int N = 100010;int e[N], ne[N], idx, head;void init(){ head = -1; idx = 0;}void add_head(int x){ e[idx] = x; ne[idx] = head; head = idx; idx++;}void add(int k, int x){ e[idx] =原创 2021-10-28 20:32:12 · 75 阅读 · 0 评论 -
洛谷P1908 逆序对(归并排序)
#include <bits/stdc++.h>using namespace std;const int N = 1e8;long long q[N];long long ans = 0;long long tmp[N];void merge_sort(long long q[], int l, int r){ if(l >= r) return; int mid = l + r >> 1; merge_sort(q, l原创 2021-10-12 14:57:18 · 236 阅读 · 0 评论 -
算法基础课
基础算法1:0-30min快速排序30-49min归并排序49min之后 二分查找原创 2021-10-11 14:27:32 · 611 阅读 · 1 评论 -
并查集的介绍与例题
并查集,顾名思义,含有三个关键元素:并(Union):合并,用于将两个集合合并起来。查(findFather):查找当前节点的根节点。集(set):集合。下面给出关键函数:初始化函数:void init(int n){ int i; for(i=1;i<=n;i++) { father[i]=i; }}查找函数:int findFather(int x){ if(x==father[x])return x; els原创 2021-10-03 11:14:05 · 51 阅读 · 0 评论