一、基础算法

1、常用代码模板

快速排序算法模板

—— 模板题 AcWing 785. 快速排序

算法步骤:

​ ①确定分界点

​ ②调整区间

​ ③递归处理左右两段

Tips:

​ ①如果输入数据量比较大的话,用scanf输入更快,不要使用cin。

​ ②只要背诵一种万能模板即可避开所有边界问题。

​ ③考试时一般不会用到快排,面试时喜欢考察。

​ ④ #include<bits/stdc++.h>包含了目前c++所包含的所有头文件 。

​ ⑤分治一般用不到,只要掌握快速排序和归并排序就行。

void quick_sort(int q[], int l, int r)
{if (l >= r) return;int i = l - 1, j = r + 1, x = q[l + r >> 1];while (i < j){do i ++ ; while (q[i] < x);do j -- ; while (q[j] > x);if (i < j) swap(q[i], q[j]);}quick_sort(q, l, j), quick_sort(q, j + 1, r);
}

归并排序算法模板

—— 模板题 AcWing 787. 归并排序

算法步骤:

​ ①确定分界点

​ ②递归排序

​ ③归并——合二为一

void merge_sort(int q[], int l, int r)
{if (l >= r) return;int mid = l + r >> 1;merge_sort(q, l, mid);merge_sort(q, mid + 1, r);// 归并的过程int k = 0, i = l, j = mid + 1;while (i <= mid && j <= r)if (q[i] <= q[j]) tmp[k ++ ] = q[i ++ ];else tmp[k ++ ] = q[j ++ ];while (i <= mid) tmp[k ++ ] = q[i ++ ];while (j <= r) tmp[k ++ ] = q[j ++ ];for (i = l, j = 0; i <= r; i ++, j ++ ) q[i] = tmp[j];
}

整数二分算法模板

—— 模板题 AcWing 789. 数的范围

Tips:

​ ①二分区间一点包含答案。

​ ②二分的时候一定是有解的,如果无解就是和题目有关,二分的模板一定保证有解。

bool check(int x) {/* ... */} // 检查x是否满足某种性质// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
// 求左边界点
int bsearch_1(int l, int r)
{while (l < r){int mid = l + r >> 1;if (check(mid)) r = mid;    // check()判断mid是否满足性质else l = mid + 1;}return l;
}
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
// 求右边界点
int bsearch_2(int l, int r)
{while (l < r){int mid = l + r + 1 >> 1;if (check(mid)) l = mid;else r = mid - 1;}return l;
}

浮点数二分算法模板

—— 模板题 AcWing 790. 数的三次方根

bool check(double x) {/* ... */} // 检查x是否满足某种性质double bsearch_3(double l, double r)
{const double eps = 1e-6;   // eps 表示精度,取决于题目对精度的要求while (r - l > eps){double mid = (l + r) / 2;if (check(mid)) r = mid;else l = mid;}return l;
}

高精度加法

—— 模板题 AcWing 791. 高精度加法

Tips:

​ ①高精度只对C++有要求

​ ②在笔试时偶尔会出现

// C = A + B, A >= 0, B >= 0
// 用引用传参会快很多
vector<int> add(vector<int> &A, vector<int> &B)
{if (A.size() < B.size()) return add(B, A);vector<int> C;int t = 0;for (int i = 0; i < A.size(); i ++ ){t += A[i];if (i < B.size()) t += B[i];C.push_back(t % 10);t /= 10;}if (t) C.push_back(t);return C;
}

高精度减法

—— 模板题 AcWing 792. 高精度减法

// C = A - B, 满足A >= B, A >= 0, B >= 0
vector<int> sub(vector<int> &A, vector<int> &B)
{vector<int> C;for (int i = 0, t = 0; i < A.size(); i ++ ){t = A[i] - t;if (i < B.size()) t -= B[i];C.push_back((t + 10) % 10);if (t < 0) t = 1;else t = 0;}// 去掉前导0while (C.size() > 1 && C.back() == 0) C.pop_back();return C;
}

高精度乘低精度

—— 模板题 AcWing 793. 高精度乘法

// C = A * b, A >= 0, b >= 0
vector<int> mul(vector<int> &A, int b)
{vector<int> C;int t = 0; // 进位for (int i = 0; i < A.size() || t; i ++ ){if (i < A.size()) t += A[i] * b;C.push_back(t % 10);t /= 10;}while (C.size() > 1 && C.back() == 0) C.pop_back();return C;
}

高精度除以低精度

—— 模板题 AcWing 794. 高精度除法

// A / b = C ... r, A >= 0, b > 0
vector<int> div(vector<int> &A, int b, int &r)
{vector<int> C;r = 0;for (int i = A.size() - 1; i >= 0; i -- ){r = r * 10 + A[i];C.push_back(r / b);r %= b;}r= reverse(C.begin(), C.end());while (C.size() > 1 && C.back() == 0) C.pop_back();return C;
}

一维前缀和

—— 模板题 AcWing 795. 前缀和

前缀和的作用:快速计算某一段数的和

tips:

​ ①ios::sync_with_stdio(false); 提高cin的读取速度、不能再使用scanf了,但依旧没有scanf快。数据输入>=100w,建议使用scanf,否则建议使用cin。

​ ②只要定义了i - 1,则下标一般从1开始。

S[i] = a[1] + a[2] + ... a[i]
a[l] + ... + a[r] = S[r] - S[l - 1]

二维前缀和

—— 模板题 AcWing 796. 子矩阵的和

S[i, j] = 第i行j列格子左上部分所有元素的和
以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵的和为:
S[x2, y2] - S[x1 - 1, y2] - S[x2, y1 - 1] + S[x1 - 1, y1 - 1]

一维差分

—— 模板题 AcWing 797. 差分

给区间[l, r]中的每个数加上c:B[l] += c, B[r + 1] -= c

二维差分

—— 模板题 AcWing 798. 差分矩阵

给以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵中的所有元素加上c:
S[x1, y1] += c, S[x2 + 1, y1] -= c, S[x1, y2 + 1] -= c, S[x2 + 1, y2 + 1] += c

位运算

—— 模板题 AcWing 801. 二进制中1的个数

tips:

​ ①把第k位移到最后一位 n>>k

​ ②看个位是几 x&1

​ ③lowbit(x):x的二进制表达式中最低位的1所对应的值

​ ④x&-x = x&(~x+1) ~x:x取反 简单应用:统计x中有多少个1

​ ⑤x = 1010 原码:1010 反码:0101 补码:0110

求n的第k位数字: n >> k & 1
返回n的最后一位1:lowbit(n) = n & -n

双指针算法

—— 模板题 AcWIng 799. 最长连续不重复子序列

—— 模板题 AcWing 800. 数组元素的目标和

tips:

​ ①算法复杂度都是O(n)

​ ②先想一个朴素算法,观察单调关系,再想双指针算法

for (int i = 0, j = 0; i < n; i ++ )
{while (j < i && check(i, j)) j ++ ;// 具体问题的逻辑
}
常见问题分类:(1) 对于一个序列,用两个指针维护一段区间(2) 对于两个序列,维护某种次序,比如归并排序中合并两个有序序列的操作

整数离散化

—— 模板题 AcWing 802. 区间和

数据离散化处理

定义:
离散化,把无限空间中有限的个体映射到有限的空间中去,以此提高算法的时空效率。

通俗的说,离散化是在不改变数据相对大小的条件下,对数据进行相应的缩小。例如:

原数据:1,999,100000,15;处理后:1,3,4,2;

原数据:{100,200},{20,50000},{1,400};

处理后:{3,4},{2,6},{1,5};

例如有时需要将数据直接作为数组下标,但因为数据太大而无法开数组时,若数据的总量相对较少时,就可以对其进行离散化处理

tips:

​ ①pair将一对值(T1和T2)组合成一个值,这一对值可以具有不同的数据类型(T1和T2),两个值可以分别用pair的两个公有函数first和second访问。

​ ②pair排序默认先按左端点排序,后按右端点排序。

​ ③c++用vector做离散化

vector<int> alls; // 存储所有待离散化的值
sort(alls.begin(), alls.end()); // 将所有值排序
alls.erase(unique(alls.begin(), alls.end()), alls.end());   // 去掉重复元素// 二分求出x对应的离散化的值
int find(int x) // 找到第一个大于等于x的位置
{int l = 0, r = alls.size() - 1;while (l < r){int mid = l + r >> 1;if (alls[mid] >= x) r = mid;else l = mid + 1;}return r + 1; // 映射到1, 2, ...n
}

区间合并

—— 模板题 AcWing 803. 区间合并

// 将所有存在交集的区间合并
void merge(vector<PII> &segs)
{vector<PII> res;sort(segs.begin(), segs.end());int st = -2e9, ed = -2e9;for (auto seg : segs)if (ed < seg.first){if (st != -2e9) res.push_back({st, ed});st = seg.first, ed = seg.second;}else ed = max(ed, seg.second);if (st != -2e9) res.push_back({st, ed});segs = res;
}

上课:明白主要思想

课下:代码整个流程弄懂、大致的背过、题目默写相关模板、写出来并调试通过

如何提高熟练度:重复写代码(删、写)、一个题目写3-5遍

二、数据结构

1、常用代码模板

单链表

—— 模板题 AcWing 826. 单链表

Tips:

​ ①scanf每次%c之前都要加上空格,防止读取空格

struct Node
{int val;Node *next;
};//在面试题中用的多,在笔试中用一般不会用,因为new Node()非常慢,用数组模拟链表很快
// head存储链表头,e[]存储节点的值,ne[]存储节点的next指针,idx表示当前用到了哪个节点
int head, e[N], ne[N], idx;// 初始化
void init()
{head = -1;idx = 0;
}// 在链表头插入一个数a,最常用的插入操作
void insert(int a)
{e[idx] = a, ne[idx] = head, head = idx ++ ;
}// 将头结点删除,需要保证头结点存在
void remove()
{head = ne[head];
}

双链表

—— 模板题 AcWing 827. 双链表

// e[]表示节点的值,l[]表示节点的左指针,r[]表示节点的右指针,idx表示当前用到了哪个节点
int e[N], l[N], r[N], idx;// 初始化
void init()
{//0是左端点,1是右端点r[0] = 1, l[1] = 0;idx = 2;
}// 在节点a的右边插入一个数x
void insert(int a, int x)
{e[idx] = x;l[idx] = a, r[idx] = r[a];l[r[a]] = idx, r[a] = idx ++ ;
}// 删除节点a
void remove(int a)
{l[r[a]] = l[a];r[l[a]] = r[a];
}

—— 模板题 AcWing 828. 模拟栈

——模板题 AcWing 3302. 表达式求值

// tt表示栈顶
int stk[N], tt = 0;// 向栈顶插入一个数
stk[ ++ tt] = x;// 从栈顶弹出一个数
tt -- ;// 栈顶的值
stk[tt];// 判断栈是否为空
if (tt > 0)
{}

队列

—— 模板题 AcWing 829. 模拟队列

1、普通队列:
// hh 表示队头,tt表示队尾
int q[N], hh = 0, tt = -1;// 向队尾插入一个数
q[ ++ tt] = x;// 从队头弹出一个数
hh ++ ;// 队头的值
q[hh];// 判断队列是否为空
if (hh <= tt)
{}
2、循坏队列
// hh 表示队头,tt表示队尾的后一个位置
int q[N], hh = 0, tt = 0;// 向队尾插入一个数
q[tt ++ ] = x;
if (tt == N) tt = 0;// 从队头弹出一个数
hh ++ ;
if (hh == N) hh = 0;// 队头的值
q[hh];// 判断队列是否为空
if (hh != tt)
{}

单调栈

—— 模板题 AcWing 830. 单调栈

常见模型:找出每个数左边离它最近的比它大/小的数
int tt = 0;
for (int i = 1; i <= n; i ++ )
{while (tt && check(stk[tt], i)) tt -- ;stk[ ++ tt] = i;
}

单调队列

—— 模板题 AcWing 154. 滑动窗口

​ 1、用普通队列该怎么做

​ 2、将队列中的没有用的元素删掉——>具有了单调性

​ 3、可以用O(1)时间从队头/队尾取出最值

Tips:

​ ①适用场景非常有限,但面试笔试喜欢考察

常见模型:找出滑动窗口中的最大值/最小值
int hh = 0, tt = -1;
for (int i = 0; i < n; i ++ )
{while (hh <= tt && check_out(q[hh])) hh ++ ;  // 判断队头是否滑出窗口while (hh <= tt && check(q[tt], i)) tt -- ;q[ ++ tt] = i;
}

KMP

—— 模板题 AcWing 831. KMP字符串

KMP算法详解
KMP算法配图详解

​ ne数组作用有两个:一是之前提到的,ne[i]的值表示下标为i的字符前的字符串最长相等前后缀的长度;

​ 二是表示该处字符不匹配时应该回溯到的字符的下标。

// s[]是长文本,p[]是模式串,n是s的长度,m是p的长度
求模式串的Next数组:
for (int i = 2, j = 0; i <= m; i ++ )
{while (j && p[i] != p[j + 1]) j = ne[j];if (p[i] == p[j + 1]) j ++ ;ne[i] = j;
}// 匹配
for (int i = 1, j = 0; i <= n; i ++ )
{while (j && s[i] != p[j + 1]) j = ne[j]; //当主串S与模式串P失配时,j=next[j],P向右移动j - next[j]if (s[i] == p[j + 1]) j ++ ;if (j == m){j = ne[j];// 匹配成功后的逻辑}
}

Trie字典树

—— 模板题 AcWing 835. Trie字符串统计

int son[N][26], cnt[N], idx;
// 0号点既是根节点,又是空节点
// son[][]存储树中每个节点的子节点
// cnt[]存储以每个节点结尾的单词数量
// idx存储当前用到的节点下标// 插入一个字符串
void insert(char *str)
{int p = 0;for (int i = 0; str[i]; i ++ ){int u = str[i] - 'a';if (!son[p][u]) son[p][u] = ++ idx;p = son[p][u];}cnt[p] ++ ;
}// 查询字符串出现的次数
int query(char *str)
{int p = 0;for (int i = 0; str[i]; i ++ ){int u = str[i] - 'a';if (!son[p][u]) return 0;p = son[p][u];}return cnt[p];
}

并查集

—— 模板题 AcWing 836. 合并集合

—— 模板题 AcWing 837. 连通块中点的数量

Tips:

​ 分类问题用并查集做

(1)朴素并查集:
int p[N]; //存储每个点的祖宗节点// 返回x的祖宗节点 + 路径压缩
int find(int x)
{if (p[x] != x) p[x] = find(p[x]);return p[x];
}// 初始化,假定节点编号是1~n
for (int i = 1; i <= n; i ++ ) p[i] = i;// 合并a和b所在的两个集合:
p[find(a)] = find(b);
(2)维护size的并查集:
int p[N], size[N];
//p[]存储每个点的祖宗节点, size[]只有祖宗节点的有意义,表示祖宗节点所在集合中的点的数量// 返回x的祖宗节点
int find(int x)
{if (p[x] != x) p[x] = find(p[x]);return p[x];
}// 初始化,假定节点编号是1~n
for (int i = 1; i <= n; i ++ )
{p[i] = i;size[i] = 1;
}// 合并a和b所在的两个集合:
size[find(b)] += size[find(a)];
p[find(a)] = find(b);
(3)维护到祖宗节点距离的并查集:
int p[N], d[N];
//p[]存储每个点的祖宗节点, d[x]存储x到p[x]的距离// 返回x的祖宗节点
int find(int x)
{if (p[x] != x){int u = find(p[x]);d[x] += d[p[x]];p[x] = u;}return p[x];
}// 初始化,假定节点编号是1~n
for (int i = 1; i <= n; i ++ )
{p[i] = i;d[i] = 0;
}// 合并a和b所在的两个集合:
p[find(a)] = find(b);
d[find(a)] = distance; // 根据具体问题,初始化find(a)的偏移量

—— 模板题 AcWing 838. 堆排序

—— 模板题 AcWing 839. 模拟堆

// h[N]存储堆中的值, h[1]是堆顶,x的左儿子是2x, 右儿子是2x + 1
// ph[k]存储第k个插入的点在堆中的位置
// hp[k]存储堆中下标是k的点是第几个插入的
int h[N], ph[N], hp[N], size;// 交换两个点,及其映射关系
void heap_swap(int a, int b)
{swap(ph[hp[a]],ph[hp[b]]);swap(hp[a], hp[b]);swap(h[a], h[b]);
}void down(int u)
{int t = u;if (u * 2 <= size && h[u * 2] < h[t]) t = u * 2;if (u * 2 + 1 <= size && h[u * 2 + 1] < h[t]) t = u * 2 + 1;if (u != t){heap_swap(u, t);down(t);}
}void up(int u)
{while (u / 2 && h[u] < h[u / 2]){heap_swap(u, u / 2);u >>= 1;}
}// O(n)建堆
for (int i = n / 2; i; i -- ) down(i);

一般哈希

—— 模板题 AcWing 840. 模拟散列表

(1) 拉链法
int h[N], e[N], ne[N], idx;// 向哈希表中插入一个数
void insert(int x)
{int k = (x % N + N) % N;e[idx] = x;ne[idx] = h[k];h[k] = idx ++ ;
}// 在哈希表中查询某个数是否存在
bool find(int x)
{int k = (x % N + N) % N;for (int i = h[k]; i != -1; i = ne[i])if (e[i] == x)return true;return false;
}
(2) 开放寻址法
int h[N];// 如果x在哈希表中,返回x的下标;如果x不在哈希表中,返回x应该插入的位置
int find(int x)
{int t = (x % N + N) % N;while (h[t] != null && h[t] != x){t ++ ;if (t == N) t = 0;}return t;
}

字符串哈希

—— 模板题 AcWing 841. 字符串哈希

核心思想:将字符串看成P进制数,P的经验值是131或13331,取这两个值的冲突概率低
小技巧:取模的数用2^64,这样直接用unsigned long long存储,溢出的结果就是取模的结果typedef unsigned long long ULL;
ULL h[N], p[N]; // h[k]存储字符串前k个字母的哈希值, p[k]存储 P^k mod 2^64// 初始化
p[0] = 1;
for (int i = 1; i <= n; i ++ )
{h[i] = h[i - 1] * P + str[i];p[i] = p[i - 1] * P;
}// 计算子串 str[l ~ r] 的哈希值
ULL get(int l, int r)
{return h[r] - h[l - 1] * p[r - l + 1];
}

C++ STL简介

vector, 变长数组,倍增的思想size()  返回元素个数empty()  返回是否为空clear()  清空front()/back()push_back()/pop_back()begin()/end()[]支持比较运算,按字典序pair<int, int>first, 第一个元素second, 第二个元素支持比较运算,以first为第一关键字,以second为第二关键字(字典序)string,字符串size()/length()  返回字符串长度empty()clear()substr(起始下标,(子串长度))  返回子串c_str()  返回字符串所在字符数组的起始地址支持 a += “def“ a += ‘c’queue, 队列size()empty()push()  向队尾插入一个元素front()  返回队头元素back()  返回队尾元素pop()  弹出队头元素priority_queue, 优先队列,默认是大根堆size()empty()push()  插入一个元素top()  返回堆顶元素pop()  弹出堆顶元素定义成小根堆的方式:priority_queue<int, vector<int>, greater<int>> q;stack, 栈size()empty()push()  向栈顶插入一个元素top()  返回栈顶元素pop()  弹出栈顶元素deque, 双端队列用的不多,速度慢,效率不高size()empty()clear()front()/back()push_back()/pop_back()push_front()/pop_front()begin()/end()[]set, map, multiset, multimap, 基于平衡二叉树(红黑树),动态维护有序序列size()empty()clear()begin()/end()++, -- 返回前驱和后继,时间复杂度 O(logn)set/multisetinsert()  插入一个数find()  查找一个数count()  返回某一个数的个数erase()(1) 输入是一个数x,删除所有x   O(k + logn)(2) 输入一个迭代器,删除这个迭代器lower_bound()/upper_bound()lower_bound(x)  返回大于等于x的最小的数的迭代器upper_bound(x)  返回大于x的最小的数的迭代器
map/multimapinsert()  插入的数是一个pairerase()  输入的参数是pair或者迭代器find()[]  注意multimap不支持此操作。 时间复杂度是 O(logn)lower_bound()/upper_bound()unordered_set, unordered_map, unordered_multiset, unordered_multimap, 哈希表和上面类似,增删改查的时间复杂度是 O(1)不支持 lower_bound()/upper_bound(), 迭代器的++,--bitset, 圧位bitset<10000> s;~, &, |, ^>>, <<==, !=[]count()  返回有多少个1any()  判断是否至少有一个1
none()  判断是否全为0set()  把所有位置成1
set(k, v)  将第k位变成v
reset()  把所有位变成0
flip()  等价于~
flip(k) 把第k位取反

三、搜索与图论

1、常用代码模板

树与图的存储

树是一种特殊的图,与图的存储方式相同。
对于无向图中的边ab,存储两条有向边a->b, b->a。
因此我们可以只考虑有向图的存储。

(1) 邻接矩阵:g[a][b] 存储边a->b

(2) 邻接表:

// 对于每个点k,开一个单链表,存储k所有可以走到的点。h[k]存储这个单链表的头结点
int h[N], e[N], ne[N], idx;// 添加一条边a->b
void add(int a, int b)
{e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}// 初始化
idx = 0;
memset(h, -1, sizeof h);

树与图的遍历

时间复杂度 O(n+m), n 表示点数,m 表示边数

(1) 深度优先遍历 —— 模板题 AcWing 846. 树的重心

int dfs(int u)
{st[u] = true; // st[u] 表示点u已经被遍历过for (int i = h[u]; i != -1; i = ne[i]){int j = e[i];if (!st[j]) dfs(j);}
}

(2) 宽度优先遍历 —— 模板题 AcWing 847. 图中点的层次

queue<int> q;
st[1] = true; // 表示1号点已经被遍历过
q.push(1);while (q.size())
{int t = q.front();q.pop();for (int i = h[t]; i != -1; i = ne[i]){int j = e[i];if (!st[j]){st[j] = true; // 表示点j已经被遍历过q.push(j);}}
}

拓扑排序

—— 模板题 AcWing 848. 有向图的拓扑序列

时间复杂度 O(n+m), n 表示点数,m 表示边数

bool topsort()
{int hh = 0, tt = -1;// d[i] 存储点i的入度for (int i = 1; i <= n; i ++ )if (!d[i])q[ ++ tt] = i;while (hh <= tt){int t = q[hh ++ ];for (int i = h[t]; i != -1; i = ne[i]){int j = e[i];if (-- d[j] == 0)q[ ++ tt] = j;}}// 如果所有点都入队了,说明存在拓扑序列;否则不存在拓扑序列。return tt == n - 1;
}

朴素dijkstra算法

—— 模板题 AcWing 849. Dijkstra求最短路 I

int g[N][N];  /  / 存储每条边
int dist[N];  // 存储1号点到每个点的最短距离
bool st[N];   // 存储每个点的最短路是否已经确定// 求1号点到n号点的最短路,如果不存在则返回-1
int dijkstra()
{memset(dist, 0x3f, sizeof dist);dist[1] = 0;for (int i = 0; i < n - 1; i ++ ){int t = -1;     // 在还未确定最短路的点中,寻找距离最小的点for (int j = 1; j <= n; j ++ )if (!st[j] && (t == -1 || dist[t] > dist[j]))t = j;// 用t更新其他点的距离for (int j = 1; j <= n; j ++ )dist[j] = min(dist[j], dist[t] + g[t][j]);st[t] = true;}if (dist[n] == 0x3f3f3f3f) return -1;return dist[n];
}

堆优化版dijkstra算法

—— 模板题 AcWing 850. Dijkstra求最短路 II

时间复杂度 O(mlogn), n 表示点数,m 表示边数

typedef pair<int, int> PII;int n;      // 点的数量
int h[N], w[N], e[N], ne[N], idx;       // 邻接表存储所有边
int dist[N];        // 存储所有点到1号点的距离
bool st[N];     // 存储每个点的最短距离是否已确定// 求1号点到n号点的最短距离,如果不存在,则返回-1
int dijkstra()
{memset(dist, 0x3f, sizeof dist);dist[1] = 0;priority_queue<PII, vector<PII>, greater<PII>> heap;heap.push({0, 1});      // first存储距离,second存储节点编号while (heap.size()){auto t = heap.top();heap.pop();int ver = t.second, distance = t.first;if (st[ver]) continue;st[ver] = true;for (int i = h[ver]; i != -1; i = ne[i]){int j = e[i];if (dist[j] > distance + w[i]){dist[j] = distance + w[i];heap.push({dist[j], j});}}  }if (dist[n] == 0x3f3f3f3f) return -1;return dist[n];
}

Bellman-Ford算法

—— 模板题 AcWing 853. 有边数限制的最短路

时间复杂度 O(nm), n 表示点数,m 表示边数

注意在模板题中需要对下面的模板稍作修改,加上备份数组,详情见模板题。

int n, m;       // n表示点数,m表示边数
int dist[N];        // dist[x]存储1到x的最短路距离struct Edge     // 边,a表示出点,b表示入点,w表示边的权重
{int a, b, w;
}edges[M];// 求1到n的最短路距离,如果无法从1走到n,则返回-1。
int bellman_ford()
{memset(dist, 0x3f, sizeof dist);dist[1] = 0;// 如果第n次迭代仍然会松弛三角不等式,就说明存在一条长度是n+1的最短路径,由抽屉原理,路径中至少存在两个相同的点,说明图中存在负权回路。// 假设 1 号点到 n 号点是可达的,每一个点同时向指向的方向出发,更新相邻的点的最短距离,通过循环 n-1 次操作,若图中不存在负环,则 1 号点一定会到达 n 号点,若图中存在负环,则在 n-1 次松弛后一定还会更新for (int i = 0; i < n; i ++ ){for (int j = 0; j < m; j ++ ){int a = edges[j].a, b = edges[j].b, w = edges[j].w;if (dist[b] > dist[a] + w)dist[b] = dist[a] + w;}}if (dist[n] > 0x3f3f3f3f / 2) return -1;return dist[n];
}

spfa 算法(队列优化的Bellman-Ford算法)

—— 模板题 AcWing 851. spfa求最短路

时间复杂度 平均情况下 O(m),最坏情况下 O(nm), n 表示点数,m 表示边数

int n;      // 总点数
int h[N], w[N], e[N], ne[N], idx;       // 邻接表存储所有边
int dist[N];        // 存储每个点到1号点的最短距离
bool st[N];     // 存储每个点是否在队列中// 求1号点到n号点的最短路距离,如果从1号点无法走到n号点则返回-1
int spfa()
{memset(dist, 0x3f, sizeof dist);dist[1] = 0;queue<int> q;q.push(1);st[1] = true;while (q.size()){auto t = q.front();q.pop();st[t] = false;for (int i = h[t]; i != -1; i = ne[i]){int j = e[i];if (dist[j] > dist[t] + w[i]){dist[j] = dist[t] + w[i];if (!st[j])     // 如果队列中已存在j,则不需要将j重复插入{q.push(j);st[j] = true;}}}}if (dist[n] == 0x3f3f3f3f) return -1;return dist[n];
}

spfa判断图中是否存在负环

—— 模板题 AcWing 852. spfa判断负环

时间复杂度是 O(nm), n 表示点数,m 表示边数

int n;      // 总点数
int h[N], w[N], e[N], ne[N], idx;       // 邻接表存储所有边
int dist[N], cnt[N];        // dist[x]存储1号点到x的最短距离,cnt[x]存储1到x的最短路中经过的点数
bool st[N];     // 存储每个点是否在队列中// 如果存在负环,则返回true,否则返回false。
bool spfa()
{// 不需要初始化dist数组// 原理:如果某条最短路径上有n个点(除了自己),那么加上自己之后一共有n+1个点,由抽屉原理一定有两个点相同,所以存在环。queue<int> q;for (int i = 1; i <= n; i ++ ){q.push(i);st[i] = true;}while (q.size()){auto t = q.front();q.pop();st[t] = false;for (int i = h[t]; i != -1; i = ne[i]){int j = e[i];if (dist[j] > dist[t] + w[i]){dist[j] = dist[t] + w[i];cnt[j] = cnt[t] + 1;if (cnt[j] >= n) return true;       // 如果从1号点到x的最短路中包含至少n个点(不包括自己),则说明存在环if (!st[j]){q.push(j);st[j] = true;}}}}return false;
}

floyd算法

—— 模板题 AcWing 854. Floyd求最短路

初始化:for (int i = 1; i <= n; i ++ )for (int j = 1; j <= n; j ++ )if (i == j) d[i][j] = 0;else d[i][j] = INF;// 算法结束后,d[a][b]表示a到b的最短距离
void floyd()
{for (int k = 1; k <= n; k ++ )for (int i = 1; i <= n; i ++ )for (int j = 1; j <= n; j ++ )d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}

朴素版prim算法

—— 模板题 AcWing 858. Prim算法求最小生成树

int n;      // n表示点数
int g[N][N];        // 邻接矩阵,存储所有边
int dist[N];        // 存储其他点到当前最小生成树的距离
bool st[N];     // 存储每个点是否已经在生成树中// 如果图不连通,则返回INF(值是0x3f3f3f3f), 否则返回最小生成树的树边权重之和
int prim()
{memset(dist, 0x3f, sizeof dist);int res = 0;for (int i = 0; i < n; i ++ ){int t = -1;for (int j = 1; j <= n; j ++ )if (!st[j] && (t == -1 || dist[t] > dist[j]))t = j;if (i && dist[t] == INF) return INF;if (i) res += dist[t];st[t] = true;for (int j = 1; j <= n; j ++ ) dist[j] = min(dist[j], g[t][j]);}return res;
}

Kruskal算法

—— 模板题 AcWing 859. Kruskal算法求最小生成树

时间复杂度是 O(mlogm), n 表示点数,m 表示边数

int n, m;       // n是点数,m是边数
int p[N];       // 并查集的父节点数组struct Edge     // 存储边
{int a, b, w;bool operator< (const Edge &W)const
{return w < W.w;
}}edges[M];int find(int x)     // 并查集核心操作
{if (p[x] != x) p[x] = find(p[x]);return p[x];
}int kruskal()
{sort(edges, edges + m);for (int i = 1; i <= n; i ++ ) p[i] = i;    // 初始化并查集int res = 0, cnt = 0;for (int i = 0; i < m; i ++ ){int a = edges[i].a, b = edges[i].b, w = edges[i].w;a = find(a), b = find(b);if (a != b)     // 如果两个连通块不连通,则将这两个连通块合并{p[a] = b;res += w;cnt ++ ;}}if (cnt < n - 1) return INF;return res;
}

染色法判别二分图

—— 模板题 AcWing 860. 染色法判定二分图

时间复杂度是 O(n+m), n 表示点数,m 表示边数

int n;      // n表示点数
int h[N], e[M], ne[M], idx;     // 邻接表存储图
int color[N];       // 表示每个点的颜色,-1表示未染色,0表示白色,1表示黑色// 参数:u表示当前节点,c表示当前点的颜色
bool dfs(int u, int c)
{color[u] = c;for (int i = h[u]; i != -1; i = ne[i]){int j = e[i];if (color[j] == -1){if (!dfs(j, !c)) return false;}else if (color[j] == c) return false;}return true;
}bool check()
{memset(color, -1, sizeof color);bool flag = true;for (int i = 1; i <= n; i ++ )if (color[i] == -1)if (!dfs(i, 0)){flag = false;break;}return flag;
}

匈牙利算法

—— 模板题 AcWing 861. 二分图的最大匹配

时间复杂度是 O(nm) ,n 表示点数,m 表示边数

int n1, n2;     // n1表示第一个集合中的点数,n2表示第二个集合中的点数
int h[N], e[M], ne[M], idx;     // 邻接表存储所有边,匈牙利算法中只会用到从第一个集合指向第二个集合的边,所以这里只用存一个方向的边
int match[N];       // 存储第二个集合中的每个点当前匹配的第一个集合中的点是哪个
bool st[N];     // 表示第二个集合中的每个点是否已经被遍历过bool find(int x)
{for (int i = h[x]; i != -1; i = ne[i]){int j = e[i];if (!st[j]){st[j] = true;if (match[j] == 0 || find(match[j])){match[j] = x;return true;}}}return false;
}// 求最大匹配数,依次枚举第一个集合中的每个点能否匹配第二个集合中的点
int res = 0;
for (int i = 1; i <= n1; i ++ )
{memset(st, false, sizeof st);if (find(i)) res ++ ;
}

四、数学知识

1、常用代码模板

试除法判定质数

—— 模板题 AcWing 866. 试除法判定质数

bool is_prime(int x)
{if (x < 2) return false;for (int i = 2; i <= x / i; i ++ )if (x % i == 0)return false;return true;
}

试除法分解质因数

—— 模板题 AcWing 867. 分解质因数

void divide(int x)
{for (int i = 2; i <= x / i; i ++ )if (x % i == 0){int s = 0;while (x % i == 0) x /= i, s ++ ;cout << i << ' ' << s << endl;}if (x > 1) cout << x << ' ' << 1 << endl;cout << endl;
}

朴素筛法求素数

—— 模板题 AcWing 868. 筛质数

int primes[N], cnt;     // primes[]存储所有素数
bool st[N];         // st[x]存储x是否被筛掉void get_primes(int n)
{for (int i = 2; i <= n; i ++ ){if (st[i]) continue;primes[cnt ++ ] = i;for (int j = i + i; j <= n; j += i)st[j] = true;}
}

线性筛法求素数

—— 模板题 AcWing 868. 筛质数

int primes[N], cnt;     // primes[]存储所有素数
bool st[N];         // st[x]存储x是否被筛掉void get_primes(int n)
{for (int i = 2; i <= n; i ++ ){if (!st[i]) primes[cnt ++ ] = i;for (int j = 0; primes[j] <= n / i; j ++ ){st[primes[j] * i] = true;if (i % primes[j] == 0) break;}}
}

试除法求所有约数

—— 模板题 AcWing 869. 试除法求约数

vector<int> get_divisors(int x)
{vector<int> res;for (int i = 1; i <= x / i; i ++ )if (x % i == 0){res.push_back(i);if (i != x / i) res.push_back(x / i);}sort(res.begin(), res.end());return res;
}

约数个数和约数之和

—— 模板题 AcWing 870. 约数个数, AcWing 871. 约数之和

如果 N = p1^c1 * p2^c2 * ... *pk^ck
约数个数: (c1 + 1) * (c2 + 1) * ... * (ck + 1)
约数之和: (p1^0 + p1^1 + ... + p1^c1) * ... * (pk^0 + pk^1 + ... + pk^ck)

欧几里得算法

—— 模板题 AcWing 872. 最大公约数

int gcd(int a, int b)
{return b ? gcd(b, a % b) : a;
}

求欧拉函数

—— 模板题 AcWing 873. 欧拉函数

int phi(int x)
{int res = x;for (int i = 2; i <= x / i; i ++ )if (x % i == 0){res = res / i * (i - 1);while (x % i == 0) x /= i;}if (x > 1) res = res / x * (x - 1);return res;
}

筛法求欧拉函数

—— 模板题 AcWing 874. 筛法求欧拉函数

int primes[N], cnt;     // primes[]存储所有素数
int euler[N];           // 存储每个数的欧拉函数
bool st[N];         // st[x]存储x是否被筛掉void get_eulers(int n)
{euler[1] = 1;for (int i = 2; i <= n; i ++ ){if (!st[i]){primes[cnt ++ ] = i;euler[i] = i - 1;}for (int j = 0; primes[j] <= n / i; j ++ ){int t = primes[j] * i;st[t] = true;if (i % primes[j] == 0){euler[t] = euler[i] * primes[j];break;}euler[t] = euler[i] * (primes[j] - 1);}}
}

快速幂

—— 模板题 AcWing 875. 快速幂

求 m^k mod p,时间复杂度 O(logk)。int qmi(int m, int k, int p)
{int res = 1 % p, t = m;while (k){if (k&1) res = res * t % p;t = t * t % p;k >>= 1;}return res;
}

扩展欧几里得算法

—— 模板题 AcWing 877. 扩展欧几里得算法

// 求x, y,使得ax + by = gcd(a, b)
int exgcd(int a, int b, int &x, int &y)
{if (!b){x = 1; y = 0;return a;}int d = exgcd(b, a % b, y, x);y -= (a/b) * x;return d;
}

中国剩余定理

// 根据中国剩余定理,如果m1,m2,…,mn不是两两互质的,那么就不存在这样的x
// 如果满足上述条件,则x = a1·M1·M1^(-1) + a2·M2·M2^(-1) + …… + an·Mn·Mn^(-1),
// 其中Mi = M / mi,M = m1·m2·…·mn,Mi^(-1)表示Mi模mi的逆

高斯消元

—— 模板题 AcWing 883. 高斯消元解线性方程组

// a[N][N]是增广矩阵
int gauss()
{int c, r;for (c = 0, r = 0; c < n; c ++ ){int t = r;for (int i = r; i < n; i ++ )   // 找到绝对值最大的行if (fabs(a[i][c]) > fabs(a[t][c]))t = i;if (fabs(a[t][c]) < eps) continue;for (int i = c; i <= n; i ++ ) swap(a[t][i], a[r][i]);      // 将绝对值最大的行换到最顶端for (int i = n; i >= c; i -- ) a[r][i] /= a[r][c];      // 将当前行的首位变成1for (int i = r + 1; i < n; i ++ )       // 用当前行将下面所有的列消成0if (fabs(a[i][c]) > eps)for (int j = n; j >= c; j -- )a[i][j] -= a[r][j] * a[i][c];r ++ ;}if (r < n){for (int i = r; i < n; i ++ )if (fabs(a[i][n]) > eps)return 2; // 无解return 1; // 有无穷多组解}for (int i = n - 1; i >= 0; i -- )for (int j = i + 1; j < n; j ++ )a[i][n] -= a[i][j] * a[j][n];return 0; // 有唯一解
}

递归法求组合数

—— 模板题 AcWing 885. 求组合数 I

// c[a][b] 表示从a个苹果中选b个的方案数
for (int i = 0; i < N; i ++ )for (int j = 0; j <= i; j ++ )if (!j) c[i][j] = 1;else c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;

通过预处理逆元的方式求组合数

—— 模板题 AcWing 886. 求组合数 II

首先预处理出所有阶乘取模的余数fact[N],以及所有阶乘取模的逆元infact[N]
如果取模的数是质数,可以用费马小定理求逆元
int qmi(int a, int k, int p)    // 快速幂模板
{int res = 1;while (k){if (k & 1) res = (LL)res * a % p;a = (LL)a * a % p;k >>= 1;}return res;
}// 预处理阶乘的余数和阶乘逆元的余数
fact[0] = infact[0] = 1;
for (int i = 1; i < N; i ++ )
{fact[i] = (LL)fact[i - 1] * i % mod;infact[i] = (LL)infact[i - 1] * qmi(i, mod - 2, mod) % mod;
}

Lucas定理

—— 模板题 AcWing 887. 求组合数 III

若p是质数,则对于任意整数 1 <= m <= n,有:C(n, m) = C(n % p, m % p) * C(n / p, m / p) (mod p)int qmi(int a, int k, int p)  // 快速幂模板
{int res = 1 % p;while (k){if (k & 1) res = (LL)res * a % p;a = (LL)a * a % p;k >>= 1;}return res;
}int C(int a, int b, int p)  // 通过定理求组合数C(a, b)
{if (a < b) return 0;LL x = 1, y = 1;  // x是分子,y是分母for (int i = a, j = 1; j <= b; i -- , j ++ ){x = (LL)x * i % p;y = (LL)y * j % p;}return x * (LL)qmi(y, p - 2, p) % p;}int lucas(LL a, LL b, int p)
{if (a < p && b < p) return C(a, b, p);return (LL)C(a % p, b % p, p) * lucas(a / p, b / p, p) % p;
}

分解质因数法求组合数

—— 模板题 AcWing 888. 求组合数 IV

当我们需要求出组合数的真实值,而非对某个数的余数时,分解质因数的方式比较好用:1. 筛法求出范围内的所有质数2. 通过 C(a, b) = a! / b! / (a - b)! 这个公式求出每个质因子的次数。 n! 中p的次数是 n / p + n / p^2 + n / p^3 + ...3. 用高精度乘法将所有质因子相乘int primes[N], cnt;     // 存储所有质数
int sum[N];     // 存储每个质数的次数
bool st[N];     // 存储每个数是否已被筛掉void get_primes(int n)      // 线性筛法求素数
{for (int i = 2; i <= n; i ++ ){if (!st[i]) primes[cnt ++ ] = i;for (int j = 0; primes[j] <= n / i; j ++ ){st[primes[j] * i] = true;if (i % primes[j] == 0) break;}}
}int get(int n, int p)       // 求n!中的次数
{int res = 0;while (n){res += n / p;n /= p;}return res;
}vector<int> mul(vector<int> a, int b)       // 高精度乘低精度模板
{vector<int> c;int t = 0;for (int i = 0; i < a.size(); i ++ ){t += a[i] * b;c.push_back(t % 10);t /= 10;}while (t){c.push_back(t % 10);t /= 10;}return c;}get_primes(a);  // 预处理范围内的所有质数for (int i = 0; i < cnt; i ++ )     // 求每个质因数的次数
{int p = primes[i];sum[i] = get(a, p) - get(b, p) - get(a - b, p);
}vector<int> res;
res.push_back(1);for (int i = 0; i < cnt; i ++ )     // 用高精度乘法将所有质因子相乘for (int j = 0; j < sum[i]; j ++ )res = mul(res, primes[i]); 

卡特兰数

—— 模板题 AcWing 889. 满足条件的01序列

给定n个0和n个1,它们按照某种顺序排成长度为2n的序列,满足任意前缀中0的个数都不少于1的个数的序列的数量为: Cat(n) = C(2n, n) / (n + 1)

NIM游戏

—— 模板题 AcWing 891. Nim游戏

给定N堆物品,第i堆物品有Ai个。两名玩家轮流行动,每次可以任选一堆,取走任意多个物品,可把一堆取光,但不能不取。取走最后一件物品者获胜。两人都采取最优策略,问先手是否必胜。

我们把这种游戏称为NIM博弈。把游戏过程中面临的状态称为局面。整局游戏第一个行动的称为先手,第二个行动的称为后手。若在某一局面下无论采取何种行动,都会输掉游戏,则称该局面必败。
所谓采取最优策略是指,若在某一局面下存在某种行动,使得行动后对面面临必败局面,则优先采取该行动。同时,这样的局面被称为必胜。我们讨论的博弈问题一般都只考虑理想情况,即两人均无失误,都采取最优策略行动时游戏的结果。
NIM博弈不存在平局,只有先手必胜和先手必败两种情况。

定理: NIM博弈先手必胜,当且仅当 A1 ^ A2 ^ … ^ An != 0

公平组合游戏ICG

若一个游戏满足:

由两名玩家交替行动;
在游戏进程的任意时刻,可以执行的合法行动与轮到哪名玩家无关;
不能行动的玩家判负;
则称该游戏为一个公平组合游戏。
NIM博弈属于公平组合游戏,但城建的棋类游戏,比如围棋,就不是公平组合游戏。因为围棋交战双方分别只能落黑子和白子,胜负判定也比较复杂,不满足条件2和条件3。

有向图游戏

给定一个有向无环图,图中有一个唯一的起点,在起点上放有一枚棋子。两名玩家交替地把这枚棋子沿有向边进行移动,每次可以移动一步,无法移动者判负。该游戏被称为有向图游戏。
任何一个公平组合游戏都可以转化为有向图游戏。具体方法是,把每个局面看成图中的一个节点,并且从每个局面向沿着合法行动能够到达的下一个局面连有向边。

Mex运算

设S表示一个非负整数集合。定义mex(S)为求出不属于集合S的最小非负整数的运算,即:
mex(S) = min{x}, x属于自然数,且x不属于S

SG函数

在有向图游戏中,对于每个节点x,设从x出发共有k条有向边,分别到达节点y1, y2, …, yk,定义SG(x)为x的后继节点y1, y2, …, yk 的SG函数值构成的集合再执行mex(S)运算的结果,即:
SG(x) = mex({SG(y1), SG(y2), …, SG(yk)})
特别地,整个有向图游戏G的SG函数值被定义为有向图游戏起点s的SG函数值,即SG(G) = SG(s)。

有向图游戏的和

—— 模板题 AcWing 893. 集合-Nim游戏

设G1, G2, …, Gm 是m个有向图游戏。定义有向图游戏G,它的行动规则是任选某个有向图游戏Gi,并在Gi上行动一步。G被称为有向图游戏G1, G2, …, Gm的和。
有向图游戏的和的SG函数值等于它包含的各个子游戏SG函数值的异或和,即:
SG(G) = SG(G1) ^ SG(G2) ^ … ^ SG(Gm)

定理

有向图游戏的某个局面必胜,当且仅当该局面对应节点的SG函数值大于0。
有向图游戏的某个局面必败,当且仅当该局面对应节点的SG函数值等于0。

五、动态规划

1、课堂笔记

DP时间复杂度 = 状态数量 * 转移计算量

一般做法: 分析状态表示(集合、属性),写出状态计算(转移方程)

01背包问题

——模板题 AcWing 2. 01背包问题

每件物品最多只用一次

结合题目理解

状态表示 f(i, j):

​ 集合:所有选法的集合 ,只从前 i 个物品中,总体积 <= j

​ 属性:集合最大值,集合最小值,数量

状态计算:

​ 集合划分:不含 i ,包含 i ,不重复(不一定要满足),不漏(一定满足)

完全背包问题

——模板题 AcWing 3. 完全背包问题

每件物品有无限个

朴素算法:

​ 可能超时

​ f[i, j] = f[i - 1, j - v[i] * k] + w[i] * k

​ k不能无限大,超过背包容量终止

优化算法:

之后与01背包问题类似优化

多重背包问题

——模板题 AcWing 4. 多重背包问题

——模板题 AcWing 5. 多重背包问题 II

每个物品有 Si 个

朴素算法与完全背包问题类似

不能直接用完全背包问题的优化方法进行优化

采用二进制进行优化

分组背包问题

——模板题 AcWing 9. 分组背包问题

每组物品有若干个,每组最多只能选一个

线性DP

数字三角形

——模板题 AcWing 898. 数字三角形

最长上升子序列

——模板题 AcWing 895. 最长上升子序列

求最长上升子序列:

——模板题 AcWing 896. 最长上升子序列 II

最长公共子序列

——模板题 AcWing 897. 最长公共子序列

最短编辑距离

——模板题 AcWing 902. 最短编辑距离

编辑距离

——模板题 AcWing 899. 编辑距离

思路与最短编辑距离类似

区间DP

——模板题 AcWing 282. 石子合并

计数类DP

——模板题 AcWing 900. 整数划分

整数问题

可以看作一个完全背包问题

数位统计DP

——模板题 AcWing 338. 计数问题

分情况讨论!

状态压缩DP

用一个二进制整数来表示某种状态

蒙德里安的梦想

——模板题 AcWing 291. 蒙德里安的梦想

j 存储i - 1列哪些行横放了1 * 2的矩形

①和②判断状态是否能够转移过来

只枚举了横放的矩形,所以列空白必须不存在连续奇数个0

最短Hamiltan路径

——模板题 AcWing 91. 最短Hamilton路径

树形DP

——模板题 AcWing 285. 没有上司的舞会

记忆化搜索

要求不存在环

代码复杂度低

已经算过的值不会重复计算

滑雪游戏

——模板题 AcWing 901. 滑雪

六、回溯

// 回朔代码模板
void backward():if (回朔点):// 这条路走到底的条件。也是递归出口保存该结果return  ;else:for (route : all_route_set)  // 逐步选择当前节点下的所有可能routeif 剪枝条件:剪枝前的操作return  ; // 不继续往下走了,退回上层,换个路再走else:// 当前路径可能是条可行路径保存当前数据  // 向下走之前要记住已经走过这个节点了。例如push当前节点backward(); // 递归发生,继续向下走一步了。回朔清理     // 该节点下的所有路径都走完了,清理堆栈,准备下一个递归。例如弹出当前节点

AcWing算法题常用代码模板相关推荐

  1. 刷算法题常用的 JS 基础扫盲

    大厂技术  高级前端  Node进阶 点击上方 程序员成长指北,关注公众号 回复1,加入高级Node交流群 介绍 此篇属于前端算法入门系列的第一篇,主要介绍常用的数组方法.字符串方法.遍历方法.高阶函 ...

  2. 算法题常用技巧C++

    刷题常用技巧C++ 常用头文件 #include <iostream> #include <cstdio> #include <fstream> #include ...

  3. java算法题常用到的一些api,含面试题+答案

    一面(电话面+后期在线coding) ①你们为什么要使用mongdoDb?你们的这个系统中涉及到哪些表? ②hytrix 的实现原理是什么?隔离策略有哪些?你们使用的是哪一些?你们项目中哪些地方使用到 ...

  4. acwing算法题--铁路与公路

    原题链接:https://www.acwing.com/problem/content/description/4077/ #include <iostream> #include < ...

  5. acwing算法题--看图做题

    原题链接:https://www.acwing.com/problem/content/3992/ 找规律题 #include<iostream>using namespace std;i ...

  6. acwing算法题--不同的数

    原题链接:https://www.acwing.com/problem/content/3991/ #include <iostream> #include <unordered_m ...

  7. acwing算法题--二维费用的背包问题

    原题链接:https://www.acwing.com/problem/content/8/ #include <iostream>using namespace std;const in ...

  8. acwing算法题--混合背包问题

    原题链接:https://www.acwing.com/problem/content/7/ #include <iostream> #include <vector>usin ...

  9. acwing算法题--多重背包问题二

    原题链接:https://www.acwing.com/problem/content/5/ #include <iostream> #include <vector>usin ...

最新文章

  1. 7-5 表格输出 (C语言)
  2. Golang 新手可能会踩的 50 个坑
  3. 检测到磁盘可能为uefi引导_Win10创意者无法更新提示“磁盘布局不受uefi固件支持”怎么办?...
  4. 冒泡法排序c语言函数模板,使用模板技术的冒泡排序
  5. 如何部署同一个Spring boot web 应用到不同的环境
  6. java 封箱_java封箱和拆箱分析
  7. (22)FPGA面试技能提升篇(MicroBlaze、PowerPC)
  8. 获取当前jvm的进程号
  9. 二倍图css,css二倍图的使用
  10. 怎么将tflite部署在安卓上_手把手教程:如何从零开始训练 TF 模型并在安卓系统上运行...
  11. 计算机 会议录用率 统计
  12. afuwin64教程_AMI刷BIOS工具下载|AFUWIN(AMI刷BIOS工具) v4.47官方最新版 附使用教程_星星软件园...
  13. 在RedHat Linux下安装惠普磁带机(转)
  14. Aras Innovator: 如何在Form中放入图片
  15. 石墨烯和碳纤维的联系与区别
  16. 读书笔记 - 《枪炮、病菌与钢铁》
  17. 京东618大促,全店快递如何批量打印
  18. hdu4416——后缀自动机
  19. 大四寒假实习——面试总结
  20. 网页设计经典色彩搭配

热门文章

  1. html5在图片中加链接,JavaScript、html5、canvas实现图片上画超链接
  2. 概率统计——重要术语及解释
  3. OpenCV基础之边缘检测与轮廓描绘
  4. 福利:生化危机6终章(1.2G)超清分享
  5. OpenCV笔记一:imread函数
  6. 服务器内存32g与64g性能区别,手机同一款,为什么32G和64G,差别大,同样都是运行内存4G的,但是64G却被叫做高配版?...
  7. win10系统如何查看WiFi密码
  8. Ecshop与企业微信的对接
  9. JavaScript实例第十六天
  10. idea 去绿色波浪线