OI & ACM 笔记:A - 基础算法

A - 基础算法 指令基础

NOI Linux 指令

返回上一级目录cd ..
返回当前用户的主目录cd ~
进入某一目录内cd <目录路径>

显示当前工作目录pwd

新建文件夹mkdir <目录文件> <新建文件夹名>

删除

  • 删除单一文件:rm <文件路径>
  • 删除目录及目录内的文件:rm -r <要删除的目录路径>

改名mv <旧文件名> <新文件名>

查看文件内容cat <文件路径>

简单查看文件信息dir <目录路径>

详细查看文件信息ls -alh <目录路径>

  • ls -a <目录路径>:显示所有文件(包括隐藏文件)。
  • ls -l <目录路径>:显示文件属性。
  • ls -h <目录路径>:将文件大小转换为常用单位(无单位默认为字节)。

提升权限

  • 使用 root 权限(最高权限)操作该命令:sudo <命令>
  • 登录到另外一个用户:su <用户名>

命令行编译g++/gcc <源代码文件名> -o <可执行文件名>

  • -std=c++11:c++11 标准。
  • -O2:O2 优化。
  • ulimit -s 128000000:开栈。
  • -Wall:显示所有警告。
  • -Wextra:检测可疑代码并生成警告。
  • -Wconversion:转型警告。

执行程序./<应用程序>

只读执行程序./<project> <A.in

只输执行程序./<project> >A.out

读输执行程序./<project> <A.in >A.out

查看执行程序运行时间time ./<应用程序>

比较文本diff <文本 A><文本 B>

A - 基础算法 语言基础

语言基础

数值范围

  • int 范围:\(< 2^{31}\)
  • unsigned int 范围:\(< 2^{32}\)
  • long long 范围:\(< 2^{63}\)
  • unsigned long long 范围:\(< 2^{64}\)

自然溢出

  • unsigned int 自然溢出:对 \(2^{32}\) 取模。
  • unsigned long long 自然溢出:对 \(2^{64}\) 取模。

输出格式

  • unsigned int 输出格式:%u
  • unsigned long long 输出格式:%llu

C++ STL

lower_bound & upper_bound

  • lower_bound(s, t, val):指向 \([s, t)\) 中第一个 \(\geq \mathrm{val}\) 的元素的迭代器,需要保证 \([s, t)\) 升序排序。
  • upper_bound(s, t, val):指向 \([s, t)\) 中第一个 \(> \mathrm{val}\) 的元素的迭代器,需要保证 \([s, t)\) 升序排序。

sort

  • sort() 的实现基于快速排序。

升序排序(默认)sort(s, t)

降序排序sort(s, t, greater<int>())

stable_sort

  • stable_sort() 的实现基于归并排序。比较次数稳定且相较于 std::sort 较少。

vector

  • vector 编号从 \(0\) 开始。
  • vector<int> num(n):指定该容器大小为 \(n\)
  • vector<int> num(n, m):指定该容器大小为 \(n\),初始值均为 \(m\)
  • V.resize(n, m):重新制定该容器大小为 \(n\),若容器变长,则以值 \(m\) 填充;若容器变短,则超出限制的元素被删除。
  • lower_bound(V.begin(), V.end(), val):指向容器中第一个 \(\geq \mathrm{val}\) 的元素的迭代器,需要保证容器升序排序。
  • upper_bound(V.begin(), V.end(), val):指向容器中第一个 \(> \mathrm{val}\) 的元素的迭代器,需要保证容器升序排序。

区间计数 upper_bound(V.begin(), V.end(), r) - lower_bound(V.begin(), V.end(), l)

priority_queue

大根堆(默认)priority_queue<int> q

小根堆priority_queue< int, vector<int>, greater<int> > q

set

升序排序(默认)set<int> s

降序排序set< int, greater<int> > s

  • s.lower_bound(val):指向容器中第一个 \(\geq \mathrm{val}\) 的元素的迭代器。
  • s.upper_bound(val):指向容器中第一个 \(> \mathrm{val}\) 的元素的迭代器。

multiset

升序排序(默认)multiset<int> s

降序排序multiset< int, greater<int> > s

  • s.erase(val):将所有数值为 \(\mathrm{val}\) 的元素删除,返回被删除的元素个数。
  • s.erase(pos):将迭代器 \(\mathrm{pos}\) 指向的元素删除。
  • 在 multiset 中删除一个数值为 \(\mathrm{val}\) 的元素,应执行 s.erase(s.find(val))
  • 使用 multiset 维护多关键字的数据,在重载小于号时,应保证两个不同的元素能被有效区分。

bitset

  • bitset 编号从 \(0\) 开始。
  • bitset 可以进行各种二进制操作,如取反 ~、与 &、或 |、异或 ^、左移 <<、右移 >>
  • b.count():返回 \(1\) 的个数。
  • b.any():查询 bitset 中是否存在 \(1\)
  • b.none():查询 bitset 中是否全 \(0\)
  • b.reset():将所有位改为 \(0\)
  • b.set():将所有位改为 \(1\)
  • b._Find_first():查询低位到高位第一个 \(1\) 的位置。
  • b._Find_next():查询当前位置之后下一个 \(1\) 的位置。

A - 基础算法 算法基础

I/O 优化

读入优化

template <class T>
inline void read(T &x) {
	static char s;
	static bool opt;
	while (s = getchar(), (s < '0' || s > '9') && s != '-');
	x = (opt = s == '-') ? 0 : s - '0';
	while (s = getchar(), s >= '0' && s <= '9') x = x * 10 + s - '0';
	if (opt) x = ~x + 1;
}

快速乘

\(\mathcal{O}(\log n)\) 快速乘

特别要注意的是,模数大小的两倍不能超过 long long 上界。

typedef long long s64;
s64 qmul(s64 a, s64 b, s64 p) {
	s64 ans = 0;
	for (; b; b >>= 1) {
		if (b & 1) ans = (ans + a) % p;
		a = 2 * a % p;
	}
	return ans;
}

\(\mathcal{O}(1)\) 快速乘

注意到:

\[a \times b \bmod p = a \times b - \left\lfloor \frac{a \times b}{p} \right\rfloor \times p \]

利用 long double 来处理 \(\left\lfloor \frac{a \times b}{p} \right\rfloor\)

虽然 \(a \times b\)\(\left\lfloor \frac{a \times b}{p} \right\rfloor \times p\) 的数值可能很大,但是两者的差一定在 \([0, p)\) 之间,我们只关心它们的前 64 位即可,这正好可以用 long long 运算的自然溢出来处理。

typedef long long s64;
s64 qmul(s64 a, s64 b, s64 p) {
	s64 c = (long double)a * b / p + 1e-8;
	s64 ans = a * b - c * p;
	if (ans < 0) ans += p;
	if (ans >= p) ans -= p;
	return ans;
}

快速幂

int qpow(int a, int b, int p) {
	int ans = 1;
	for (; b; b >>= 1) {
		if (b & 1) ans = 1ll * ans * a % p;
		a = 1ll * a * a % p;
	}
	return ans;
}

二分

  • >> 1 向下取整,/2 向零取整。
  • 在整数域上进行二分时:
    • 若分成的区间为 \([l, \mathrm{mid}], [\mathrm{mid} + 1, r]\)mid = (l + r) >> 1
    • 若分成的区间为 \([l, \mathrm{mid} - 1], [\mathrm{mid}, r]\)mid = (l + r + 1) >> 1
  • 在实数域上进行二分时,mid = (l + r) / 2

二叉树

\(n_0\)\(n_2\) 的关系\(n_0 = n_2 + 1\)

\(n_0\)\(n_2\) 的关系证明

\[n = n_0 + n_1 + n_2 = 1 + n_1 + 2n_2 \Rightarrow n_0 = n_2 + 1 \]

贪心

贪心的常见证明方法

  • 微扰法(邻项交换)。
  • 范围缩放法。
  • 决策包容性。
  • 反证法。
  • 数学归纳法。
posted @ 2022-12-19 10:24  Calculatelove  阅读(268)  评论(0编辑  收藏  举报