# [《从 C++98 到 C++20,寻觅甜甜的语法糖们》](https://www.luogu.com.cn/blog/AccRobin/grammar-candies#)
# 这篇文章对《从 C++98 到 C++20,寻觅甜甜的语法糖们》稍有改动
- find(bg,ed,val)
- 返回指向第一个等于 $val$ 的元素的指针。
- 时间复杂度 $O(n)$。
- **后文所有序列操作的函数,都以 $n$ 代指 $ed−bg$。**
- fill(bg,ed,val)
- 将 $bg \sim ed$ 之间的所有元素赋值为 $val$。
- 复杂度为 $O(n)$,常数略大于 `memset`。
- 在 `val = 0x3f` 时常数与 `memset` 相同。(存疑)
- 常用于弥补 `memset` 无法赋值的问题,如赋值一个数组为 $1$。
- max_element/min_element(bg,ed)
- 返回指向 $bg \sim ed$ 中最大/最小的元素的指针。
- 时间复杂度 $O(n)$。
- 第三个参数可传入比较函数。
- 求数组最大值就可以直接写:`*max_element(a+1,a+n+1)`
- nth_element(bg,md,ed):
- 将 $bg \sim ed$ 中的内容重新分配顺序,$\le$ md 的元素在 $bg \sim md$,$\ge$ md 的元素都在 $md \sim ed$。
- 时间复杂度 $O(n)$,需要 $O(n)$ 的额外空间。
- 第四个参数为比较函数,若不传则默认 `less<>()`。
- 常用于线性求序列中的第 $k$ 大,常用于实现替罪羊树。
- stable_sort(bg,ed)
- 对 $bg \sim ed$ 进行 稳定 排序。
- 时间复杂度 $O(n log n)$,要 $O(n)$ 的额外空间。
- 当空间不足时使用 $O(n log_2 n)$ 的双调排序。
- next_permutation(bg,ed)
- 将 $bg \sim ed$ 更改为下一个排列,并返回 $1$。
- 若 $bg \sim ed$ 已经是最后一个排列,那么返回 $0$。
- 下一个排列的定义为字典序严格大于当前排列的下一个排列。
- 时间复杂度 $O(n)$。
- 事实上 $bg \sim ed$ 不一定要是排列,可以存在相同元素。
- 常用于枚举全排列:
```cpp
do{
// ...
}while(next_permutation(p,p+n));
```
- `prev_permutation(bg,ed)` 可以求出上一个排列。
- merge(bg1,ed1,bg2,ed2,bg3)
- $bg1 \sim ed1$ 和 $bg2 \sim ed2$ 是两个有序序列,对其进行归并并存入 `bg3`。
- 不能够原地归并,若要原地归并请使用 `inplace_merge`。
- 时间复杂度 $O(ed1−bg1+ed2−bg2)$。
- 可以传入第六参数作为比较函数。
- inplace_merge(bg,md,ed)
- 将 $bg \sim md$ 和 $md \sim ed$ 归并排序,并存入 `bg`。
- 时间复杂度 $O(n)$,需要 $O(n)$ 的额外空间。
- 当空间不足时使用 $O(n log n)$ 的原地排序。
- 常数较小,可能比手写的还快。
- 可以传入第四个参数作为比较函数。
- 常用于 `CDQ` 分治等分治算法,非常好用。
- count(bg,ed,val)
- 返回 $bg \sim ed$ 中等于 $val$ 的元素的个数。
时间复杂度 $O(n)$。
- count_if(bg,ed,func)
- 返回 $bg \sim ed$ 中使得函数 `func` 返回值为 $\true$ 的元素的个数。
- 时间复杂度 $O(n \times f)$,$f$ 为 `func` 的复杂度。
- 常用的 `func` 有:`islower/isupper/isdigit` 等。
- replace(bg,ed,val1,val2)
- 将 $bg \sim ed$ 中所有等于 $val1$ 的元素替换为 $val2$。
- 时间复杂度 $O(n)$。
- for_each(bg,ed,func)
- 对 $bg \sim ed$ 中所有元素执行函数 `func`。
- 时间复杂度 $O(n \times f)$。
- 其实没啥用,就是能压行。
- accumulate(bg,ed,val)
- 将 $bg \sim ed$ 中的所有所有元素与初始值 $val$ 相加,返回这个和。
- 时间复杂度 $O(n)$。
- 可以传入第四个参数作为加法。
- 可以用于求序列和,但注意,该函数返回值与 $val$ 类型一致,意味着你要注意 `long long` 的问题:
```cpp
accumulate(bg,ed,0);//返回值是 int,可能溢出
accumulate(bg,ed,0ll);//返回值是 long long
```
- fabs(x)
- 返回 $∣x∣$。
- 注意,对浮点运算请都使用 `fabs` 而不是 `abs`,因为有可能你调用的是 `abs(int)`。
- ceil(x)
- 返回 $⌈x⌉$
- 其返回值依旧是浮点类型,输出时注意格式。
- floor(x)
- 返回 $⌊x⌋$
- 其返回值依旧是浮点类型,输出时注意格式。
- shuffle(bg,ed,gen)
- 打乱 $bg \sim ed$ 的顺序,`gen` 是一个随机数生成器(mt19937)。
- 时间复杂度 $O(n)$。
- C++11 之后请尽量使用 `shuffle` 而不是 `random_shuffle`。
- is_sorted(bg,ed)
- 判断 $bg \sim ed$ 是否升序排序。
- 时间复杂度 $O(n)$。
- minmax(a,b)
- 返回一个 `pair<>`,其 `first` 为 $\min(a,b)$,`second` 为 $\max(a,b)$。
- 时间复杂度 $O(1)$。
- 常用于无向图存边的去重问题。
- exp2(x)
- 返回 $2^x$。
- log2(x)
- 返回 $log_2(x)$
- hypot(x,y)
- 返回 $\sqrt {x^2 + y^2}$
- 常用于求两点之间的距离,非常方便。
- hypot(x,y,z)
- 返回 $\sqrt {x^2 + y^2 + z^2}$
- 复杂度 O(1)。
- 常用来求三维中两点距离。
- mt19937
- 一个类型,作为随机数生成器。
- 其构造函数应传入一个数字作为随机种子,使用时用法和 $rand$ 相同。
- 生成 `unsigned int` 范围内的随机数。
```cpp
mt19937 gen(123456); //123456 为随机种子
int x = gen()%10000; //x will in [0,10000]
uint32_t y = gen(); //normally y will in [0,2^32]
```
- 随机种子通常为时间相关,下面的非常常用,建议背过
```cpp
mt19937 gen(chrono::system_clock::now().time_since_epoch().count());//chrono 在头文件 <chrono> 中
```
- uniform_int_distribution<T>(L,R)
- 随机数发生器,每次调用时传入一个 `mt19937`,返回一个 $L \sim R$ 之间的整数,类型为 $T$,若 $T$ 为空则默认为 `int`。
- uniform_real_distribution<T>(L,R)
- 随机数发生器,每次调用时传入一个 `mt19937`,返回一个 $L \sim R$ 之间的实数,类型为 $T$,若 $T$ 为空则默认为 `double`。
- gcd(x,y) 或 lcm(x,y)
- 返回 $\gcd(|x|,|y|)$ 或 $\operatorname {lcm}(|x|,|y|)$ 的值。
- 复杂度对数级别的。
- 保证了返回值的符号是正。
- $\operatorname {lcm}$ 的实现是先除后乘。
- popcount(x)
- 返回无符号整形 $x$ 在二进制下 $1$ 的个数。
- 时间复杂度有说 $O( \log \log x)$ 的,也有说 $O(1)$ 的,一定比手写的快。
- 使用 `__builtin_popcount` 实现,但会检查传入的参数是否为无符号整形。
-
```cpp
countl_zero(x);//从最高位起连续的 0 的数量
countr_zero(x);//从最低位起连续的 0 的数量
countl_one(x);//从最高位起连续的 1 的数量
countr_one(x);//从最低位起连续的 1 的数量
```
- bit_width(x)
- 当 $x = 0$ 时返回 $0$,否则返回 $1+⌊log2(x)⌋$。
- 即二进制下 $x$ 的位数。
- 复杂度 $O(1)$。
- bit_floor(x)/bit_ceil(x)
- 返回不超过 $x$ 的最大的 $2$ 的整次幂 / 不小于 $x$ 的最小的 $2$ 的整次幂。
- 复杂度 $O(1)$。
- has_single_bit(x)
- 返回 $x$ 是否为 $2$ 的整次幂,相当于 `popcount(x)==1`。
- 复杂度 $O(1)$。
- numbers 库
头文件 `<numbers>`,命名空间 `std::numbers` 中提供了大量的数学常数:
| 代码表示 | 数学表示 |
| :----------- | :----------- |
| e_v | $e$ |
| log2e_v | $log_{2}e$ |
| pi_v | $\pi$ |
| log10e_v | $log_{10}e$ |
| inv_pi_v | $\frac{1}{\pi}$ |
| inv_sqrtpi_v | $\frac{1}{\sqrt{\pi}}$ |
| ln2_v | $\operatorname{ln}2$ |
| ln10_v | $\operatorname{ln}10$ |
| sqrt2_v | $\sqrt{2}$ |
| sqrt3_v | $\sqrt{3}$ |
| inv_sqrt3_v | $\frac{1}{\sqrt{3}}$ |
| egamma_v | 欧拉-马斯克若尼常数 $γ$ |
| phi_v | 黄金比 $ϕ= \frac{\sqrt5+1}{2}$(注意这里是加号!!!) |
- 这些都是类模板,调用时请填入类型:
```cpp
int main(){
std::cout<<std::fixed<<std::setprecision(9)<<std::numbers::pi_v<double><<'\n';
}
```
去掉末尾的 `_v` 后直接就是一个常量:
```cpp
cout<<numbers::e<<'\n';
```