算法竞赛常用模板
基础算法
快速幂
1 | typedef long long ll; |
二分查找
给定长度为n的数组(\(n\geq 1\))
问题1:找到值为value的元素的下标
1 | int BinarySearch(int array[], int n, int value) { |
问题2:找到第一个值为value的元素的下标
这时候遇到相等也不能直接返回,只能排除掉右侧的所有数。
数组的长度为 1 或 2 时,middle
为 0. 若array[0]
为要找的数,则right
将被赋值为 -1,循环结束,left
为答案。数组长度为 2 且array[1]
为要找的数时,left
将被赋值为 1,回到数组长度为 1 的情况。
因此最后再判断一下left
是否为要找的数,如果是则返回,否则答案不存在。
1 | int BinarySearch(int array[], int n, int value) { |
问题3:找到最后一个值为value的元素的下标
这就是问题2的倒序版本。改动两个地方即可
if (array[middle] >= value)
中的等号去掉;if (right >= 0 && array[right] == value) {return right;}
问题4:找到第一个大于等于value的下标
在问题2中,我们的策略是让left
刚好为第一个大于等于value的数的下标,而让right
刚好为第一个小于value的数的下标。因此只需要去掉最后判断答案存在的array[left] == value
条件即可。
问题5:找到最后一个小于等于value的下标
与问题4同理,去掉问题3中最后判断答案存在的array[right] == value
条件。
数论
欧拉筛
1 | bool is_prime[MAXN]; |
辗转相除法求最大公因数(Greatest Common Divisor)
最大公因数的算法是辗转相除法,基于一个原理:如果\(a>b\)则\(gcd(a,b)=gcd(b,a-b)\).
如果\(a-b>b\),那么就继续相减到\(a-b<b\)为止,所以直接\(gcd(a,b)=gcd(b,a\bmod b)\).
代码:
1 | int gcd(int a, int b) { |
最小公倍数(Least Common Multiple)
两个数的最大公因数(Greatest Common Divisor)就是它们质因数的交集的乘积
考虑最小公倍数的性质。最小公倍数必须被\(a\)或\(b\)整除,也就是说最小公倍数必须同时包含这两数的所有质因数,所以是它们质因数的并集的乘积。怎样得到这个乘积?\(a\times b\),然后容斥除掉共同的质因数\(gcd(a,b)\)就好了。 \[ lcm(a,b)=\dfrac{a\times b}{gcd(a,b)} \] 实际编程中一般先除后乘,防止溢出。
代码:
1 | int lcm(int a, int b) { |
裴蜀定理
裴蜀定理,又称贝祖定理(Bézout's lemma)。是一个关于最大公约数的定理。
其内容是:
设 \(a,b\) 是不全为零的整数,则存在整数 \(x,y\), 使得 \(ax+by=\gcd(a,b)\).
证明:
1 | int gcd(int a, int b) { |
在函数返回之前,存在\(b=0\). 这时显然有\(x=1,y=0\)使得 \[ a\cdot 1+0\cdot 0=gcd(a,0) \] 0 和任何数的最大公约数都等于原数。
当\(b>0\)时,有\(gcd(a,b)=gcd(b,a\bmod b)\). 假设存在\(x,y\)使得 \[ bx+(a\bmod b)y=gcd(b,a\bmod b) \] 且 \[ a\bmod b=a-b\cdot \left\lfloor \dfrac{a}{b} \right\rfloor \] 所以 \[ \begin{aligned} bx+(a\bmod b)y&=bx+\left(a-b\cdot \left\lfloor \dfrac{a}{b} \right\rfloor\right)y\\ &=ay-b\left(x-\left\lfloor \dfrac{a}{b} \right\rfloor y\right ) \end{aligned} \] 令\(x'=y,\ y'=x-\left\lfloor \dfrac{a}{b} \right\rfloor y\),可得 \[ ax'+by'=gcd(a,b) \] 用归纳法即可得证。
参考:https://www.cnblogs.com/fusiwei/p/11775503.html
扩展欧几里得
为什么叫它扩展欧几里得呢?因为它就是在欧几里得算法(辗转相除法)求得\(gcd(a,b)\)的基础上,像上面裴蜀定理的证明那样倒着回溯找了一组\(x,y\)满足 \[ ax+by=gcd(a,b) \] 具体代码请看下面的线性同余方程。
线性同余方程(线性丢番图方程)
形如\(ax\equiv c\pmod b\)的方程被称为线性同余方程 (Congruence Equation)。
求解方法
根据以下两个定理,我们可以求出同余方程 \(ax \equiv c \pmod b\) 的解。
定理 1:方程 \(ax+by=c\) 与方程 \(ax \equiv c \pmod b\) 是等价的,有整数解的充要条件为 \(\gcd(a,b) \mid c\)。
根据定理 1,方程 \(ax+by=c\),我们可以先用扩展欧几里得算法求出一组 \(x_0,y_0\),也就是 \(ax_0+by_0=\gcd(a,b)\),然后两边同时除以 \(\gcd(a,b)\),再乘 \(c\)。然后就得到了方程 \(a\dfrac{c}{\gcd(a,b)}x_0+b\dfrac{c}{\gcd(a,b)}y_0=c\),然后我们就找到了方程的一个解。
定理 2:若 \(\gcd(a,b)=1\),且 \(x_0\)、\(y_0\) 为方程 \(ax+by=c\) 的一组解,则该方程的任意解可表示为:\(x=x_0+bt\),\(y=y_0-at\), 且对任意整数 \(t\) 都成立。
根据定理 2,可以求出方程的所有解。但在实际问题中,我们往往被要求求出一个最小整数解,也就是一个特解 \(x=(x \bmod t+t) \bmod t\),其中 \(t=\dfrac{b}{\gcd(a,b)}\)。
1 | int ex_gcd(int a, int b, int& x, int& y) { |
常用 STL
比较两个 string 是否相等
string (1) | int compare (const string& str) const noexcept; |
---|---|
substrings (2) | int compare (size_t pos, size_t len, const string& str, size_t subpos, size_t sublen = npos) const; |
c-string (3) | int compare (const char* s) const; int compare (size_t pos, size_t len, const char* s) const; |
buffer (4) | int compare (size_t pos, size_t len, const char* s, size_t n) const; |
返回值
value | relation between compared string and comparing string |
---|---|
0 |
They compare equal |
<0 |
Either the value of the first character that does not match is lower in the compared string, or all compared characters match but the compared string is shorter. |
>0 |
Either the value of the first character that does not match is greater in the compared string, or all compared characters match but the compared string is longer. |
从容器中删除指定的元素
从字符串中删除某些字符
1 |
|
1 | template <class ForwardIterator, class T> |