![](https://img-blog.csdnimg.cn/20201014180756757.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
算法学习
文章平均质量分 50
CCloth
这个作者很懒,什么都没留下…
展开
-
Java快读快写模板
首先需要import java.io.*这个包,之后创建如下两个对象,分别用于输入和输出:StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));快读:in.nextToken()原创 2022-05-18 19:57:56 · 326 阅读 · 0 评论 -
可持久化线段树总结
一、可持久化线段树其实是由不同版本的线段树组成的。二、第i棵线段树就是前i个点的权值线段树。三、对于一个新版本的线段树只有logn个结点发生了变化,所以只需要新开logn个结点。四、普通可持久化线段树只能解决静态问题,如果涉及修改结点值需要用到树套树。以255. 第K小数为例,放一个模板:#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>原创 2022-04-02 19:05:40 · 527 阅读 · 0 评论 -
多重背包的各种优化
一、朴素做法最朴素的解法就是枚举这种物品具体要选多少个,时间复杂度为O(n*v*m),n为物品种类,v为背包体积,m为物品个数。以4. 多重背包问题 I为例,贴一个代码:#include <bits/stdc++.h>using namespace std;int w[105], v[105], num[105], dp[105];signed main(){ int n, m; cin >> n >> m; for(int原创 2022-03-30 09:49:56 · 734 阅读 · 0 评论 -
究极无敌火车头
#pragma GCC diagnostic error "-std=c++11"#pragma GCC target("avx")#pragma GCC optimize(3)#pragma GCC optimize("Ofast")#pragma GCC optimize("inline")#pragma GCC optimize("-fgcse")#pragma GCC optimize("-fgcse-lm")#pragma GCC optimize("-fipa-sra")#pr.转载 2022-03-05 19:49:59 · 258 阅读 · 0 评论 -
网络流之EK算法求最大流
求最大流的算法有很多种,EK算法就是其中较简单的一种,这个算法没有进行太多的优化,时间复杂度是O(nm^2)。这个算法的核心就是不断去维护残量图。先对原图建一个残量图,初始残量图就是每条边都加一条反向的0权边,之后进行若干次bfs,每次bfs都去寻找一条从起点到终点的通路,找到以后通路上的各边权减去最小边权,同时反向边加上最小边权,这可能使得某些边的权为0,当边权为0说明这条路已经不能再有流量了,也就是条断边。随着bfs次数增多,这个图最终会变得不再连通,此时就得到了答案了,答案就是之前每次找到的最小边原创 2022-02-24 14:12:18 · 440 阅读 · 0 评论 -
最近公共祖先之树上倍增求法
一、问题引入最近公共祖先(LCA)是求有根树上两点的深度最低的祖先节点,如下图,点5和点2的最近公共祖先为点4,点5和点3的最近公共祖先为点1,点5和点1的最近公共祖先为点1。二、朴素算法知道LCA定义后考虑最暴力的求解方法,可以先让在下面的点一层一层往上爬,直到两点具有相同深度(高度),之后两点同时一层一层往上爬,直到两点相同,这个相同的点就是最近公共祖先,若有m次询问,该算法时间复杂度为O(nm),显然过于暴力了。三、树上倍增算法朴素算法中找祖先节点都是一层一层地找,这样原创 2022-02-14 11:53:42 · 543 阅读 · 1 评论 -
最小圆覆盖算法总结
一、定义什么是最小圆覆盖?其实和最小矩形覆盖定义是类似的,给出一个点集,求能覆盖住所有点的最小圆。二、两种算法求最小圆覆盖有两种算法,分别是增量法和模拟退火,个人推荐增量法,它的精度更高一些,且时间复杂度是稳定的线性级(点的顺序打乱后),所以下面也主要介绍增量法的原理。增量法前置知识1. 圆上三点确定唯一的一个圆。这个道理很简单,考虑三角形外接圆就行。2. 若已有某个点集的最小圆覆盖,向该点集中再加入一个圆外的点,这时最小圆会被更新,这个点一定出现在新的最小圆的边界上。反原创 2022-02-12 21:45:32 · 6615 阅读 · 1 评论 -
最小瓶颈生成树
定义:给出加权无向图,求一棵最大边权值尽量小的生成树。可以转化为最小生成树问题,最小生成树不仅可以得到最小的权值之和,其最大边权也为生成树中最大边权最小的。但是要注意的是最小瓶颈生成树不一定是最小生成树,但最小生成树一定是最小瓶颈生成树。考虑小边的重边,显然可以得到结论。之后可以引入最小瓶颈路,定义为:给出加权无向图的两个结点u和v,求从u到v的一条路径,使得路径上权值最大的边的权值尽量小。有一个重要的结论:无向图中,任意两个结点的最小瓶颈路肯定在最小生成树上。因此,在用kruskal算原创 2022-02-09 23:00:45 · 1432 阅读 · 0 评论 -
与圆有关算法总结
一、两圆位置关系两圆间位置关系有五种,相离,外切,相交,内切,内含,利用圆心距d和半径差以及半径和的大小关系来判定。二、三角形内切圆三角形内切圆的圆心是三条角平分线的交点,因此可以转化为求直线交点问题,任取两角平分线交点即为圆心,得到圆心后利用叉乘求出圆心到边的距离就是半径。在引入向量这个概念后求角平分线也十分简单,先求两条边的向量,然后全部单位化,最后作向量加和就是角平分线的向量。三、三角形外接圆三角形外接圆的圆心是三条垂直平分线的交点,同样转为求两直线交点问题,因此要先求出至少两原创 2022-02-08 16:42:26 · 1732 阅读 · 0 评论 -
Pick定理总结
一、定理内容Pick定理是一个非常简单的结论:s = a + b / 2 - 1,其中s是格点多边形的面积,a是多边形内部格点数,b是多边形边界上格点数。一般情况下都是用这个公式计算多边形内部格点个数,因为多边形面积和边界上格点数都可以很方便地求出。面积通过叉乘求出,边界上格点数通过gcd求出。同时通过这个公式可以知道格点多边形面积要么是个整数,要么是整数+0.5的形式。二、相关习题1. Triangle 51Nod3149这道是pick定理的裸题了,多边形固定为三角形,不过数据有些原创 2022-01-30 15:53:12 · 969 阅读 · 0 评论 -
旋转卡壳算法总结
一、历史背景1978年, M.I. Shamos's Ph.D. 的论文"Computational Geometry"标志着计算机科学的这一领域的诞生。 当时他发表成果的是一个寻找凸多边形直径的一个非常简单的算法, 即根据多边形的一对点距离的最大值来确定。后来直径演化为由一对对踵点对来确定。 Shamos提出了一个简单的O(n)时间的算法来确定一个凸n角形的对踵点对。 因为他们最多只有 3n/2 对, 直径可以在O(n)时间内算出。如...原创 2022-01-28 21:32:46 · 2492 阅读 · 1 评论 -
凸包算法总结
一、定义:凸包是一个相对于点集的概念,对于一个已经确定的点集,凸包就是由其中某些点构成的一个子集,这个子集中的点构成一个凸多边形,该多边形完全包围点集中所有点。关于凸包有一个形象的比喻:把点集中各点看作钉子,拿一个橡皮筋套住所有的钉子,最终橡皮筋就是一个凸包,使橡皮筋绷紧的钉子就是凸包中的顶点。二、求法:目前比较常见的两种求法分别为Graham扫描法和Andrew算法,由于两个算法都需要对点进行排序,因此它们的时间复杂度均为O(nlogn)...原创 2022-01-24 15:34:50 · 5042 阅读 · 1 评论 -
闵可夫斯基和总结
定义:给定两个点集A,B,定义点集C为{ c| c = a+b,a∈A,b∈B},两点间的加法为x坐标对应相加,y坐标对应相加,点集C即为A,B的闵可夫斯基和。性质:1. 凸集A和凸集B的闵可夫斯基和一定还是凸集。 可以利用凸集定义来证明,在凸集中任取两点其连线上的点一定全部出现在凸集内。 2. 两个凸包的闵可夫斯基和的凸包是对原来两个凸包的各边重排序。 如下图所示,考虑第一个凸包上的点4和第二个凸包上的...原创 2021-11-10 19:45:43 · 4370 阅读 · 0 评论 -
半平面交模板总结
概念:什么是半平面?半平面实际上就是一条有方向的直线,不过它还包括这条直线一侧(具体哪侧自行设置)的全部区域。那半平面交的概念也呼之欲出了,就是这些半平面覆盖区域的交集。作用: 1. 求多边形的核。(能看到所有点的位置) 2. 求凸多边形最大内切圆。(二分) 3. 解决线性规划问题。(矩形切割面积)注意事项: 1.该模板中半平面的直线方向逆时针区域为半平面覆盖区域。 2. 半平面交的区域一定是个凸多边形...原创 2021-11-04 20:43:05 · 257 阅读 · 0 评论 -
st表总结
长度为n的数组,m次询问区间最值,可能都会想到用线段树,然而线段树每次查询复杂度为O(logn),且代码十分冗长,如果查询次数m较大可能就会超时。现在介绍一种短小精悍的数据结构——st表。它的复杂度较低,预处理复杂度为O(nlogn),查询复杂度为O(1),在很多次询问的情况下相当好用。st表需要维护一个二维数组f[i][j],表示从第i位开始2^j长度的区间内最值,当我们有了这个数组后就可以O(1)地查询了。现在考虑如果得到这个数组,首先可以发现长度为2^j的区间可以均分为两个长度为2^(j-1)的区原创 2021-10-22 10:22:41 · 165 阅读 · 0 评论 -
(含证明)后缀数组之height数组应用
相信做过几道后缀数组题的人都深有体会,求出来的sa、rank数组用处不大,真正有用的是height数组。下面总结一下目前遇到的height数组的用法。1. 求字符串两后缀最长公共前缀 求后缀i与后缀j的最长公共前缀长度,也就是min(height[rank[i]+1], height[rank[i]+2, ......, height[rank[j]]),假设rank[i] < rank[j]的情况下。只需要证明出传递性就得证,传递性为:如果有三个字符串, 按字典序排序,lcp(...原创 2021-10-20 15:53:25 · 329 阅读 · 0 评论 -
后缀数组总结
后缀数组(suffix array)是解决字符串问题非常有力的工具,主要是为了得到三个数组,分别是sa[i],rank[i],height[i]。先对字符串的各后缀进行排序,sa[i]表示排序后第i名的后缀它开始的位置,rank[i]表示从i这个位置往后的后缀它的排名是多少,显然sa和rank数组互逆,如果已知sa[i] = t,则rank[t] = i,height[i]表示排完序后第i个后缀和第i-1个后缀的lcp(最长公共前缀)长度。具体算法实现大致可分为两类,一种是基于倍增+基数排序的思想,复杂原创 2021-10-19 15:24:12 · 125 阅读 · 0 评论 -
并查集删点总结
并查集删点操作需要借助虚点,实际上也就是一个映射罢了。通过index[i]表示i点经过映射后的编号,规定访问一个节点时只能通过它的编号index[i]来访问,初始时将各点的index[i]置为i,表示还未进行删点操作时都映射到本身,在删除点i时,将点i映射到一个虚节点上,即index[i] = m(m为虚节点编号),同时father[index[i]] = index[i] (表示删除点i后i点独立),之后所有涉及到点i的操作都用index[i]来代替,即m。这样的好处在于find()函数不需要修改原创 2021-10-09 19:30:43 · 493 阅读 · 2 评论 -
AC自动机算法总结
前言:类似kmp,ac自动机也是个字符串匹配算法,不过kmp只能单模式串与文本串的匹配,ac自动机可以实现多模式串与文本串的匹配。ac自动机需要两个前置知识点:kmp和trie。但实际上用到的只有trie罢了,感觉和kmp关系并不大,至少我记的模板是这样的。分三步: 1.构建trie树这部分就是普通的字典树插入操作,一模一样的。void insert(){ int now = 0, len = strlen(word); for(int i = 0; i <...原创 2021-10-08 15:55:21 · 231 阅读 · 0 评论 -
扩展kmp算法总结
扩展kmp是用来处理这样一类问题的:有一个文本串S,一个模式串T,求对于S串每一个后缀与T串的最长公共前缀。这个算法的时间复杂度和kmp一样,都是O(n)的。最终答案保存于extend[i]中,extend[i]表示S串从i开始的后缀与T串最长公共前缀长度。如果遍历extend数组,统计extend[i]等于strlen(T)的出现次数,那它就实现了kmp的功能,因此称其为扩展kmp算法。以P5410 【模板】扩展 KMP(Z 函数) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)这道原创 2021-10-06 14:43:19 · 354 阅读 · 0 评论 -
manacher算法总结
manacher是求最长回文子串的算法,时间复杂度仅为O(n)。在了解其原理之前先考虑求最长回文子串的朴素做法:中心扩展法。中心扩展法很简单,就是枚举每个点,暴力地向两边匹配,不能匹配时就停止,复杂度O(n^2)。而manacher就是对中心扩展法的优化版本,其核心思想在于充分利用已找到的回文串来减少中心扩展匹配次数。粗略介绍一下大体思路:考虑字符串abababa,从1开始标号,为举例方便只考虑奇数长度回文子串。开始时用中心扩展法暴力地跑完第3个字符'a'时,可以得到以第1个,第2个以及第3个字符为原创 2021-10-01 11:18:13 · 131 阅读 · 0 评论 -
最小(大)表示法模板总结
最小(大)表示法主要是用来得到字符串循环移位后字典序最小(大)的字符串。例如,给你一个字符串 s = “SKYLONG”,然后我们将这个字符串一步步地往左移:SKYLONG 1KYLONGS 2YLONGSK 3LONGSKY 4ONGSKYL 5NGSKYLO 6GSKYLON 7可以发现字典序最小的字符串是7,字典序最大的字符串是3,最小(大)表示法就是在O(n)的复杂度内得到这些信息的算法。由于这个算法模板性较强,就直接记录模板了://最小表示法int get_mins原创 2021-09-27 20:51:35 · 114 阅读 · 0 评论 -
kmp算法——深入理解next数组
求next数组是kmp算法中不可或缺的一步,以next[i]为例,其具体含义为str[1~i]中前缀与后缀能匹配的最长长度。注意这里的前后缀不能是整个字符串,不然的话所有的next[i]都等于i了,没有意义。还有这里的next[i]只是最长的长度,比它小的长度有没有匹配并不确定。求next数组的模板:for(int i = 2, j = 0; i <= len; i++){ while(j && s[j+1] != s[i]) j = _next[j]; if(s[原创 2021-08-31 17:25:41 · 375 阅读 · 0 评论 -
线段树模板总结
线段树是一种可以快速处理区间问题的数据结构,主要利用了分治的思想,并且线段树十分灵活,可以搭配其他算法解决更复杂的问题。线段树常用函数://建树与修改操作最后一定要push_up(id)来更新数据//修改与查询操作一定要push_down(id, ln, rn)下推lazy标记 void push_down(int id, int ln, int rn)//下推标记{ if(lazy[id] != 0) { lazy[id<<1] += lazy[id]; lazy原创 2021-08-22 10:32:01 · 107 阅读 · 0 评论 -
树状数组模板总结
树状数组是一个能够快速解决单点修改、区间查询的数据结构,具有代码短、不容易出bug的优点。树状数组能解决的问题线段树都能解决,但线段树能解决的问题树状数组大部分都解决不了,例如更新并维护区间最值问题。以acwing1264为例,介绍常用模板:#include <iostream>#include <cstdio>#include <algorithm>#define lowbit(x) (x&-x)//这里一定要加括号,防止运算优先级不同带来的问题原创 2021-08-22 09:28:19 · 445 阅读 · 1 评论 -
离散化总结
离散化是一个在不改变一串数字相对大小关系的前提下,将比较大的数字转化为比较小的数字的技巧。有时我们并不需要知道各数字确切的大小,我们只需要保存下来它们之间的大小关系即可,这时候就需要用到离散化。例如给出数列:9555000057800045760006060989989887,经离散化后得到:3 2 1 4。通过stl实现的离散化模板:#include <iostream>#include <cstdio>#include <algorithm>#i...原创 2021-08-20 11:28:55 · 193 阅读 · 0 评论 -
树形dp总结
树形dp是一类在树上作状态转移的问题。一般情况下,如果题目求的是最大值/最小值/数量等可以用dp解决的问题且明确给出一棵树,都可以考虑尝试树形dp解法。核心思想:1. 利用子节点信息更新当前节点。一般先进行dfs,此时所有子节点信息都已更新完毕,之后利用子节点状态dp[son]更新状态dp[now]。 2. 利用当前节点信息更新子节点。一般先用dp[now]更新dp[son],在更新前son的父节点信息都已更新完毕,之后dfs下去遍历整棵树。可以发现,两种思想都...原创 2021-08-12 23:42:15 · 207 阅读 · 0 评论 -
数位dp总结
数位dp是一类比较特殊的问题,模板性很强,主要解决区间计数问题。一般情况下题目会询问区间[L,R]中满足某种性质的数有多少个。 首先以HDU3555 Bomb为例,题意大概是寻找1~n中包含“49”的数字个数,例如249、4900等都是符合题意的数字。考虑暴搜枚举每一个数,时间复杂度大概是O(log10(n)*n),显然会超时。但是如果按位暴搜,枚举每一位可能出现的数字,时间复杂度大概是O(10^(log10(n))),比上一个暴搜快了不少,但依旧会超时。以n=2345为例...原创 2021-08-09 20:28:59 · 176 阅读 · 2 评论 -
程序设计竞赛中oj平台常见报错总结
1. Runtime Error:可能的原因是数组开太小导致越界、运算时出现除0的情况、非void函数无返回值。2. Wrong Answer:输出结果错误。3. Time原创 2021-08-07 00:51:40 · 2127 阅读 · 0 评论 -
(持续更新)一些图论的结论
有关最小生成树: 1. 边权均不相同的无向图最小生成树唯一。 2.同一个图不同最小生成树的边权重序列相同。 证明思路:所有边权均不相同的无向图最小生成树是唯一的证明_霁月难逢 彩云易散-CSDN博客_只要无向连通图中没有权值相同的边,则其最小生成树唯一...原创 2021-07-29 21:22:53 · 316 阅读 · 0 评论 -
非严格次小生成树思路
求法如下: 1. 先建一棵最小生成树。 2. 枚举所有没用到的边,依次加入MST中,每次都会构成一个环。 3. 找到环上除新加入边以外的最长边,从MST中删除。 4. 当所有没用到的边遍历完,取最小值即为次小生成树的权值和。证明见:(非严格)次小生成树 - 知乎 (zhihu.com)...原创 2021-07-29 16:05:48 · 160 阅读 · 0 评论 -
树的直径总结
一. 定义原创 2021-07-28 11:40:40 · 339 阅读 · 0 评论 -
最小生成树总结
目前还不够全面,将持续更新...Prime算法:#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>using namespace std;//自环和重边(取边权最小值)不会对prime算法产生影响 //对于已经存在的边,将它们的边权赋值为0即可,之后还是按原来的方法求解 int mp[5005][5005], dis[5005];boo.原创 2021-07-26 15:31:06 · 123 阅读 · 0 评论 -
单调栈总结
最近第一次正式接触了这种数据结构,深感原理奇妙,故记录学习心得。一. 单调栈的类别 有四类,分别是严格单调递增栈,严格单调递减栈,非严格单调递增栈,非严格单调递减栈。以下结论无需记忆,理解后画图现推即可:严格单调递增栈可以寻找右边第一个小于等于a[i]的元素(出栈前更新)或左边第一个小于a[i]的元素(入栈前更新),严格单调递减栈可以寻找右边第一个大于等于a[i]的元素(出栈前更新)或左边第一个大于a[i]的元素(入栈前更新),非严格单调递增栈可以寻...原创 2021-07-26 11:52:40 · 138 阅读 · 0 评论