
ACM知识(硬货)
文章平均质量分 59
ACM知识
Dαīsч
这个作者很懒,真的什么都没留下…………
展开
-
动态规划(树形dp)
#### 四、树形dp##### (一)、基础树形$dp$是在树的$dfs$中进行$dp$, 在树形$dp$中,我们动态规划的过程大概就是先递归访问所有子树,再在根上合并,我们求解的往往是所有的在子树范围内的最优解##### (二)、例题1、子树大小(1)、题意:计算每个点的子树的大小(2)、题解:状态表示:$sz[u]$代表$u$为根的子树大小状态转移:$sz[u]=1+\sum sz[v]$,指本节点的子树大小等于子节点的所有子树大小之和加一```cppint sz原创 2022-07-04 10:56:44 · 851 阅读 · 0 评论 -
动态规划(区间dp)
#### 三、区间$dp$##### (一)、基础1、特点:(1)、合并:将两个或多个部分进行整合,能将问题分解为能两两合并的形式(2)、求解:对整个问题设最优值,枚举合并点,将问题分解为左右两个部分,最后合并两个部分的最优值得到原问题的最优值(3)、复杂度:大多为$O(n^3)$,因此区间$dp$的数据范围一般在$100$左右2、套路:第一层循环枚举区间长度,第二层循环枚举区间左端点,右端点也固定下来,第三层循环枚举区间的分割点状态表示:$dp[i][j]$表示区间$[i,j]原创 2022-07-02 19:33:52 · 324 阅读 · 0 评论 -
线代(高斯消元法、线性基)
一、高斯消元法1、将问题转化为矩阵方程,再转化为多个n元一次方程,从而使用高斯消元法使用高斯消元法的关键在于构造增广矩阵2、需求解的未知数可能是很多类型,例如浮点型、01型(1)、异或类型解bitseta[maxn]; //a数组代表增广矩阵的系数,常数项在最后int ans[maxn], Free[maxn], cnt; //ans代表最后方程组的解,Free和cnt是自由元int Gauss(int equ, int var) //equ个...原创 2022-06-28 20:04:18 · 656 阅读 · 0 评论 -
数学(快速幂)
一、快速幂通过快速幂,我们计算a^8时,不再是a*a*a*a*a*a*a*a,而是a*a,a^2*a^2,a^4*a^4,这样我们求a^b将是O(log b)的复杂度ll quick_pow(ll a, ll b){ ll ans = 1; while (b) { if (b & 1) ans = (ans * a) % mod; b >>= 1; a = (a * a) % mod; } return ans;}二、矩阵快速幂利用快速幂,可以求一个矩阵(方阵.原创 2022-06-28 09:13:36 · 124 阅读 · 0 评论 -
博弈论入门
一、基础1、公平组合游戏:是一个满足以下条件的游戏:由两名玩家交替行动;任意时刻每名玩家可进行的的操作规则相同;游戏中的同一个状态不可能多次抵达,游戏以玩家无法行动为结束,且游戏一定会在有限步后以非平局结束2、先手必胜状态和先手必败状态,必胜点(N)和必败点(P):(1)、如果后手有一个以上的必败点,那么前驱是必胜点(2)、如果后手全为必胜点,那么前驱为必败点由此可以进行NP分析3、博弈图:给定一个有向图,在图中唯一的起点处有一个棋子,双方轮流按照有向图的边移动棋子,当一方无法移动棋子原创 2022-06-27 20:43:08 · 1022 阅读 · 1 评论 -
图论(树的直径)
一、基础树中最远的两个结点之间的距离被称为树的直径,连接这两点的路径被称为树的最长链(也称直径)二、两次遍历求直径1、从任意一个结点出发,通过bfs或者dfs对树进行一次遍历,求出与出发点距离最远的结点,记为p,这就是树的直径的一端2、从结点p出发,通过bfs和dfs对树再进行一次遍历,求出与p距离最远的结点,记为q3、那么p到q的路径就是树的一条直径,因为p一定是直径的一端,否则总能找到一条更长的链。在第二步遍历过程中,可以记录下来每个点第一次被访问时的前驱节点,最后从q回溯到p即可得到直原创 2022-06-23 13:25:16 · 306 阅读 · 0 评论 -
图论(最近公共祖先LCA)
一、基础1、定义:在一棵有根树上,对于一个结点z,既是x的祖先,也是y的祖先,那么z是x,y的公共祖先,如果z在x,y的所有公共祖先中深度最大的,我们称之为最近公共祖先,记z = LCA(x,y)2、暴力寻找(最坏时间复杂度O(n)):(1)、从x向上走到根节点,并且标记经过的结点,然后令y向上走到根节点,当第一次遇到已标记的点时,就找到了LCA(x,y)(2)、令x,y中较深的点先向上走到x,y等深处,然后同时向上访问,直到访问到同一结点,该结点就是LCA(x,y)二、树上倍增法求LCA原创 2022-06-22 18:46:51 · 238 阅读 · 0 评论 -
数论(逆元及其相关定理)
一、定理1、裴蜀定理(贝祖定理)定理:如果aaa、bbb是整数,那么一定存在整数xxx、yyy使得ax+by=gcd(a,b)ax + by = gcd(a, b)ax+by=gcd(a,b)也就是说如果ax+by=max + by = max+by=m有解,那么mmm一定是gcd(a,b)gcd(a, b)gcd(a,b)的若干倍特别的,当mmm等于1时,ax+by=1ax + by = 1ax+by=1,那么gcd(a,b)=1gcd(a, b) = 1gcd(a,b)=1,即aaa,bbb原创 2022-05-10 11:09:56 · 1510 阅读 · 0 评论 -
数论(最大公约数、素数筛、欧拉函数)
一、最大公约数(gcd)ll gcd(ll x, ll y){ return y ? gcd(y, x % y) : x;}gcd(a,b,c)=gcd(a,b-a,c-b) 可多数推广二、素数筛(欧拉筛,用于欧拉函数)int least[maxn], prime[maxn], phi[maxn], tot;void euler(int n){ int i, j; for (i = 2; i <= n; i++) { if (!least[i]) {原创 2022-02-12 12:47:05 · 320 阅读 · 0 评论 -
图论(Tarjan算法与无向图)
一、基础1、割点:若从图中删除节点x(以及所有与x关联的边之后),图将被分成不相连的子图,那么称 x 为图的割点2、割边(桥):若从图中删除边e之后,图将分裂成两个不相连的子图,那么称e为图的割边或桥3、时间戳:用来标记图中每个节点在进行深度优先搜索时被访问的时间顺序,用 dfn[x] 来表示4、追溯值:表示从当前节点x作为根节点出发,能够访问到的所有节点中,时间戳最小的值,用 low[x]来表示计算追溯值:(1)、先令low[x] = dfn[x](2)、若搜索树上x是y的父原创 2022-04-12 21:15:40 · 2506 阅读 · 2 评论 -
图论(Tarjan算法与有向图)
一、基础1、流图:给定有向图G,如果从G中一个顶点出发可以到达图中所有点,则称G是一个流图,记为(G,r),其中r称为流图的源点2、强连通图:对一个有向图,如果图中任意两个结点x,y,既存在x到y的路径,也存在y到x的路径,则称该有向图是强连通图3、强连通分量:有向图的极大连通子图被称为强连通分量,记为SCC4、追溯值:x的追溯值low[x]定义为满足以下条件的节点的最小的时间戳:(1)、该点在栈中;(2)、存在一条从以x为根的子树出发的有向边,以该点为终点计算方法:(1)、当节原创 2022-04-17 19:16:01 · 651 阅读 · 0 评论 -
图论(多源最短路径)
一、Floyd-Warshall算法可以存在负权值的边,但不可存在负环对于图的最短路径满足最优子结构:路径p是从i到j的一条最短路径,结点k是路径p上的中间结点,那么从i到k是一条最短路径、从k到j也是一条最短路径在动态规划过程中,以每一个点为k点(中介),看是否可以松弛dis数组int dis[maxn][maxn];int pre[maxn][maxn];memset(dis, 0x3f, sizeof(dis));for (int i = 0; i < m; i++)原创 2022-04-07 21:08:32 · 838 阅读 · 0 评论 -
图论(单源最短路径)
一、基础二、Bellman-Ford算法struct edge //边{ int u, v; int cost;}edge[maxn];int dis[maxn], pre[maxn]; //跑完Bellaman_Ford后,dis数组是从源点s到各点的最短路径,pre记录路径int n, m, s;int Bellman_Ford(){ for (int i = 1; i <= n; ++i) //初始化 dis[i] = (i == s ? 0 : inf);原创 2022-04-06 22:40:27 · 3420 阅读 · 0 评论 -
图论(最小生成树)
一、基础1、如果T是无环的,而且连通了图G中的所有顶点,那么我们称这样的树为图G的生成树,如果这个树是所有生成树中边权之和最小的,那么这个树称为最小生成树2、对于最小生成树的贪心策略,可以用如下的通用方法来表述:在通用方法中,在每个时刻生长出最小生成树的一条边(向集合A添加边),在整个策略实施过程中,维护一个边集合A满足:在每遍循环之前,A是某棵最小生成树的一个子集。对于这样的每个边,称为安全边,把安全边添加到集合A中不会破坏A的循环不变式3、无向图的一个切割是对集合V的一个划分,如下图,称为(原创 2022-04-05 20:30:44 · 880 阅读 · 0 评论 -
图论(拓扑排序)
//基础拓扑排序bfs实现,仅一种满足的顺序int in[maxn], ans[maxn], n; //in代表入度个数,ans代表依次入度为0的数vector<int>vec[105];queue<int>que;void tuopu(){ int j = 1, i; for (i = 1; i <= n; i++) { if (in[i] == 0) que.push(i); } while (!que.empty()) { int .原创 2022-01-23 21:02:22 · 452 阅读 · 0 评论 -
图论(基本的图算法)
一、图的表示对于图G=(V,E),可以用两种标准表示方法表示,一种表示法将图作为邻接链表的组合,另一种表示法则将图作为邻接矩阵来看待。邻接矩阵:将两点是否可以到达(到达所需费用)存在一个二维数组中特点:快速访问两点间是否有有边向连;占用内存大,通常用于稠密图(边数接近顶点树平方)中邻接链表:用链表存与第i个顶点相连的数字,通常使用vec数组或者链式前向星优点:内存小;无法快速判断是否有边,常用于稀疏图二、广度优先搜索三、深度优先搜索...原创 2022-04-04 21:50:57 · 1983 阅读 · 0 评论 -
图论(图、树基本知识)
一、图1、图主要分为有向图和无向图2、有向图G是一个二元组(V,E),其中V是有限集,而E是V上的二元关系。集合V称为图的顶点集,集合E称为图的边集,图中可能出现自环,即顶点相同的边3、在无向图G=(V,E)中,边集E由无序的顶点对组成(而不是有序对),在无向图中不允许存在自环4、如果(u,v)是有向图G=(V,E)中的一条边,则称(u,v)射出\离开顶点u,射入\进入顶点v;如果(u,v)是无向图G=(V,E)中的一条边,则称顶点u,v关联;如果(u,v)是图G=(V,E)中的一条边,则称原创 2022-04-04 20:16:33 · 2765 阅读 · 0 评论 -
数据结构(可持久化线段树)
一、可持久化的数据结构如果想知道数据集在任意时刻的历史状态(即能保存每次改变前的状态和改变后的状态),那么就需要使用可持久化的数据结构如果在每次操作后都直接拷贝所有数据,那么时空复杂度过大,但是我们会发现,每次进行修改(如线段树的单点修改)时,只会影响一部分节点(如一条链)的值,所以我们可以只创建发生改变的部分的副本,不拷贝其他部分二、可持久化线段树1、可持久化线段树:又称函数式线段树(意味着我们可以像函数一样访问每个n个版本的线段树),在每次单点更新时,都会产生O(logn)个新节点,也就原创 2022-05-08 17:01:48 · 2136 阅读 · 0 评论 -
数据结构(线段树)
线段树是一种 二叉搜索树,它将一段区间划分为若干单位区间,每一个节点都储存着一个区间。用线段树维护的问题必须满足区间加法,这类似于分治法,线段树将大区间分为小区间,分别求解小区间得到...原创 2022-03-28 19:43:15 · 838 阅读 · 0 评论 -
数据结构(字典树)
一、字典树字典树是一种用于实现字符串快速检索的多叉树结构,又称前缀树、Trie下面的字典树以字符串为例:字典树的每个结点都存储有若干个指针,如果在插入或者检索的过程中,扫描(历遍)到一个字符c,就沿着当前结点的c字符指针向下走nex数组的第一维是指针的编号,第二维是可能出现的字符(如a~z对应0~26),数组的内容存储下一个指针的编号ans数组记录能到达该点(以到该点的字符串为前缀)的字符串的个数send数组记录在该点结尾的字符串的个数(可以开成bool数组记录是否存在到该点的字符串原创 2022-04-29 20:37:14 · 338 阅读 · 0 评论 -
数据结构(树状数组)
树状数组是一种存储方式,比较方便的读写//区间查询int a[maxn], c[maxn];int lowbit(int x){ return x & (-x);}int getsum(int x){ int sum = 0; for (; x; x -= lowbit(x)) sum += c[x]; return sum;}void add(int x){ for (; x < maxn; x += lowbit(x)) c[x]++;}int原创 2022-02-03 21:07:11 · 1361 阅读 · 0 评论 -
数据结构(单调栈、单调队列)
单调栈单调队列的核心就是保持栈(队列)的单调性,每加入一个元素,如果之前的元素不符合单调性,那么就取出之前的元素,加入新元素,并记录信息。//单调栈,寻找数组中每个元素后第一个比它大的元素之前的元素个数void solve(){ int i,n,temp; ll ans = 0; stack<int>stk; scanf("%d", &n); for (i = 0; i < n; i++) { scanf("%d", &temp); while原创 2022-02-17 09:43:56 · 217 阅读 · 0 评论 -
数据结构(并查集)
简单并查集主要是解决相互连通的多个群体,一般分为三个部分:初始化,寻找根find,合并根mergefor (int i = 1; i <= n; i++){// 初始化,每个点刚开始的根节点是自己本身 fa[i] = i; }int find(int x){ while (x != fa[x]) x = fa[x]; reutrn x;}//int find(int x){ return fa[x] == x ? x : fi原创 2022-01-18 21:42:54 · 434 阅读 · 0 评论 -
散列表(哈希)应用
一、给出一串数以及一个数字CC,要求计算出所有A - B = CA−B=C的数对的个数(不同位置的数字一样的数对算不同的数对)其实本题可以直接用map存ll a[prime], n, m, ans;struct node{ ll x; //当前数字(已经hash) int y; //数字出现次数}ha[prime]; //hash表int find(ll x) //找到x的位置{ int y = abs(x) % prime; //除法散列法(x可...原创 2022-03-28 10:52:08 · 294 阅读 · 0 评论 -
散列表(hashmap)
一、直接寻址表1.直接寻址:适用于全域U比较小时,直接让关键字对应hashmap(数组)的下标。2.为了表示动态集合,我们可以用数组(或称为直接寻址表),其中每个位置称为槽,对应全域U中的一个关键字,槽k指向集合中一个关键字为k的元素二、散列表1.当U很大时,无法直接在数组中表示,那么就需要使用散列表,在散列方式下,元素存放在槽hash(k)中,即利用散列函数(hash)由关键字k计算出槽的位置,hash(k)被称为散列值。简言之,散列函数缩小了数组下标的范围2.对数组来说,易访问,难插原创 2022-03-27 21:26:49 · 952 阅读 · 0 评论 -
动态规划和贪心算法
动态规划问题的第二个性质是子问题空间必须足够“小”,也就是说,问题的递归算法会求解相同的子问题,而不是一直生成新的子问题(分治法求解的问题在每一步递归都生成全新的子问题),由于子问题的求解依赖于更小的子问题的求解,我们将子问题的规模按大小排序,按由小至大的顺序进行求解,这样在求解某一个子问题时会依赖于上一个求解的子问题。两个问题都用到了子问题,而最长简单子路径的子问题是相关的,而最短路径的子问题是无关的,这里无关是指:同一个原问题的一个子问题不影响另一个子问题的解。原创 2022-04-02 19:59:16 · 10928 阅读 · 0 评论 -
动态规划入门
动态规划算法 (biancheng.net)原创 2022-01-21 11:31:52 · 410 阅读 · 0 评论 -
字符串(字符串匹配)
一、字符串匹配问题、基础1、假设文本是一个长度为n的数组T,而模式是长度为m的数组P,我们希望在文本T中寻找模式P如果P出现在T中的第s个位置,那么我们称其有效偏移为s,在其他不匹配的位置称为无效偏移2、如果字符串w是字符串x的前缀,可以记作,后缀可以记为引理:如果x、y都是z的后缀,如果x.size<y.size那么x是y的后缀;如果x.size=y.size则x=y3、如果应用暴力匹配,那么对每个偏移量都会进行匹配,那么复杂度二、Rabin-Karp算法1、利用字符串的原创 2022-04-09 18:56:32 · 2422 阅读 · 0 评论 -
二分&三分
一、整数集合上二分(1)、写法有很多,但下面这种方法可以始终保持答案在二分区间内,二分结束条件对应的值恰好在答案所处位置,还可以很自然地处理无解情况(2)、这种写法的二分有两种形式:一个是在单增序列中找大于等于x的最小的一个int l = 0, r = n - 1, mid;while (l < r){ mid = (l + r) >> 1; if (num[mid] >= x) { r = mid; } else { l = mid + 1原创 2022-04-18 18:24:30 · 325 阅读 · 0 评论 -
杂(倍增)
一、倍增思想在我们进行递推时,如果状态空间(ans出现的所有可能集合)很大,通常线性递推无法满足时间和空间复杂度的要求那么我们可以通过成倍增长的方式,只递推状态空间在2的整数次幂位置上的值作为代表,当我们需要其他位置上的值时,我们通过“任意整数可以表示成若干个2的次幂项的和”这一性质,对答案进行相加求解,这也就要求我们递推的问题的状态空间关于2的次幂具有可划分性倍增与二进制划分两个思想相互结合,降低了求解很多问题的时间和空间复杂度,快速幂就是其中一个体现例如:现在需要从A到B,距离未知(可原创 2022-04-25 18:50:03 · 410 阅读 · 0 评论 -
杂(位运算)
一、补码32位补码 int(十进制) int(十六进制) unsigned int 0111......1111 2147483647 0x7fffffff 2147483647 00111111重复四次 1061109567 0x3f3f3f3f 1061109567 1111......1111 -1 0xffffffff 4294967295 1000......0000 -2147483648 \原创 2022-04-17 21:23:53 · 277 阅读 · 0 评论 -
杂(逆序对)
一、归并排序在归并排序中,当我们在merge中把数组逐步放到temp数组中,如果左半部分放则说明没有逆序,如果右半部分放入则会“产生”逆序对,数量是mid-i+1个int a[maxn];int temp[maxn];ll merge(int l, int mid, int r){ ll sum = 0; int i = l, j = mid + 1; for (int k = l; k <= r; k++) { if ((j > r) || (i <= mi.原创 2022-04-23 21:24:40 · 294 阅读 · 0 评论 -
杂(分治法)
在分治策略中,我们递归地求解一个问题,每层递归应用如下步骤:(1)、分解:划分为一些子问题,子问题的形式与原问题一致,规模更小(2)、解决:递归求解子问题,当子问题足够小的时候,停止递归直接求解(3)、合并:将子问题的解组合成原问题当子问题足够大,需要递归求解时,我们称之为递归情况;当子问题变得足够小,不需要递归时,称之为基本情况并归排序void Merge(int a[], int l, int mid, int r){ int i, j, k; int n = mid原创 2022-03-17 20:15:35 · 392 阅读 · 0 评论 -
杂(双指针)
1、又称尺取法,即在一个区间内使用两个指针,需要判断是否可以使用双指针2、如何判断是否可以使用尺取法?对所选取区间进行判断之后,我们可以明确如何进一步有方向地推进区间端点以求解满足条件的区间,如果已经判断了目前所选取的区间,但却无法确定所要求解的区间如何进一步得到根据其端点得到,那么尺取法便是不可行的3、双指针的关键在与左右指针该如何移动,如何得到答案int l = 1, r = 0;while (l <= n){ int check = 0; while (l <=原创 2022-05-04 20:25:56 · 296 阅读 · 0 评论 -
杂(插入排序、并归排序)
一、插入排序话不多说,直接上c++代码int a[7] = { 7,8,1,5,4,21,3 };int i, j;for (i = 1; i < 7; i++){ int key = a[i]; j = i - 1; while (j >= 0 && a[j] > key) //改变a[j]<key会降序排序 { a[j + 1] = a[j]; j--; } a[j + 1] = key;}我们可以发现每次循原创 2022-03-14 20:08:16 · 1057 阅读 · 0 评论 -
icpc交互题和文件题
一、文件题#include<fstream>int main(){ Meta; ifstream fin("hamming.in"); //使用fin输入,不可以在函数内输入 int t = 1; fin >> t; while (t--) { //...... } return 0;}int main(){ Meta; freopen("hamming.in", "r", stdin); //输入重定向,在原创 2022-03-25 21:54:24 · 1031 阅读 · 0 评论