「数据结构」线段树
线段树($Segment\ Tree$)是一种基于分治思想的__二叉树__形数据结构,可以用于__区间__上的数据维护,它可以维护以下值
左偏树($Leftist\ Tree$),是一种 __可以合并的堆状结构__,支持以下操作
树状数组($Binary\ Indexed\ Trees$)是一个维护__前缀和__的数据结构,需要支持以下操作
战神留的还有一道「P3378」堆,但是是模板,就不用多说了吧
模板地址: GitHub
1 | LL gcd(LL a, LL b) { |
lcm(a, b) = a / gcd(a, b) * b
目标: 寻找一对整数$(x, y)$,使$ax+by=gcd(a,b)$
1 | void exgcd(LL a, LL b, LL& d, LL& x, LL& y) { |
$ax+by=c$且$x,y$全为正整数,则当且仅当$gcd(a, b)|c$
1 | bool vis[maxn]; |
1 | void getprime(int n) { |
$$
\pi(x) \sim \frac{x}{\ln x}
$$
原理:费马小定理
若$a^{n-1}\equiv 1\pmod n$,$a$取值越多,可以近似认为$n$为质数
使用二次探测定理改进卡卡迈尔数(合数$n$对于任何正整数$b$,都满足$gcd(b, n)=1\ \ b^{n-1}\equiv 1\pmod n$)的bug
1 | LL Random(LL n) { return (LL)((double)rand() / RAND_MAX * n + 0.5); } |
$$
(a + b)\bmod n = ((a\bmod n) + (b\bmod n))\bmod n\\
(a - b)\bmod n = ((a\bmod n) - (b\bmod n) + n)\bmod n\\
ab\mod n = (a\bmod n)(b\bmod n)\bmod n
$$
1 | LL mul_mod(LL a, LL b, LL n){ |
1 | LL pow_mod(LL a, LL p, LL n) { |
使用位运算:
1 | LL pow_mod(LL a, LL p, LL n) { |
$$\varphi(n)=n(1-\frac{1}{p_1})(1-\frac{1}{p_2})…(1-\frac{1}{p_k})$$
$\varphi(n)$表示不超过$n$且与$n$互质的整数个数
1 | int euler_phi(int n) { |
1 | int phi[maxn]; |
若$gcd(a, n) = 1$,则$a^{\varphi(n)}\equiv 1\pmod n$
若$p$为质数,则$a^{p-1}\equiv 1\pmod p$
若$p$为质数,则$(p-1)!\equiv -1\pmod p$
$$a\div b\bmod n = a\times b^{-1}\bmod n$$
$b^{-1}$称为$b$在模$n$意义下的逆元
使用费马小定理, $a^{-1} = a^{n - 2}$
递归求解
1 | LL inv(LL a, LL n) { |
1 | int inv_table[maxn]; |
$ax\equiv b\pmod n$可以化为$ax+ny=b$使用扩展欧拉定理解决
求解$x\equiv a_i\pmod {m_i}$满足$m_i$两两互质
1 | LL crt(int n, int* a, int* m) { |
$m_i$不一定两两互质
1 | LL excrt(LL n, LL* a, LL* m) { |
求解$a^x\equiv b\pmod n$满足$n$为质数
1 | int log_mod(int a, int b, int n) { |
整除分块可以对后面的莫比乌斯反演提供很大的优化
通过枚举可以发现$\lfloor \frac{n}{i} \rfloor$的结果会出现分块现象
例如$n=10$时
$\ \ \ i\ \ \ \ 1\ \ 2\ 3\ 4\ 5\ 6\ 7\ 8\ 9\ 10\ 11\ 12\ 13\ …$
$\lfloor \frac{n}{i} \rfloor\ 10\ 5\ 3\ 2\ 2\ 1\ 1\ 1\ 1\ 1\ \ \ 0\ \ \ 0\ \ \ 0\ \ \ …$不难发现,每个块的右端点为$r=\lfloor \frac{n}{t}\rfloor (t=\lfloor \frac{n}{i}\rfloor)$
$$
\mu(n) =
\begin{cases}
1, & n=1 \\
(-1)^r, & n=p_1p_2p_3…p_r(\text{$p_i$为互不相同的质数}) \\
0, & else
\end{cases}
$$
性质:
$$\sum_{d|n}{\mu(d)}=[n=1]$$
$$\sum_{d|n}{\frac{\mu(d)}{d}}=\frac{\varphi(n)}{n}$$
线性筛:
1 | int mu[maxn], vis[maxn]; |
$???$就一道紫题$???$,还是$D1T2\ ???$
NOIp2017的题比NOIp2018的题好做一点
表面上是数论,其实就是个__动态规划__
首先设$A = (n, a) \ \ B = (m, b)$
可以证明$B \subseteq A$
$proof:$
我们设$x\in A$且$x$不能被$A$集合内除它以外的元素组成。
然后我们假设$x \notin B$,那么就说明$B$集合中必然存在一些元素能够组成$x$。
那么这些元素至少存在一个不在集合$A$内并且不能被集合$A$里的元素组成的数(因为如果不存在的话集合$A$内的元素就可以组成$x$了),可以看到这与集合$B$的定义产生了矛盾。
综上所述,$A$集合内不能被其它数组成的数必然存在于$B$集合内
$Q.E.D$
然后动态规划dp[i]
表示$i$面值最多能被几张钱表示
则若其不能被表示dp[i] = -inf
能表示且只有它自己则dp[i] = 1
初始化dp[] = -inf; dp[0] = 0
状态转移方程为dp[j] = max(dp[j], dp[j - a[i]] + 1)
1 |
|
使用__并查集和埃氏筛法__(埃拉托斯特尼筛法)即可
具体操作是边筛边合并集合
1 |
|
类似于$NOIp2017\ D1T1$ 小凯的疑惑,推柿子即可
首先$l(l+1)(l+2)…(r-1)r$可以表示为$l\times 10^? + (l + 1)\times 10^? + … + r\times 10^?$
同时我们知道$10$的若干次方除以$9$的余数__恒为__$1$
所以$l(l+1)(l+2)…(r-1)r$除以$9$的余数就等于$l + (l + 1) + … + (r - 1) + r$的余数
并且$l,l+1,…,r$为等差数列,公差为$1$
运用等差数列求和公式即可求解
$a_1 = l\ d = 1$
$n = r - l + 1$
$S_n = n\times a_1 + n\times (n - 1)\times \frac{d}{2}$
所以
$$
\boxed{Ans = n\times l + n\times (n - 1) \div 2}
$$
另外要边算边取模,除以$2$要变成乘模$9$下的逆元$5$
所以公式如下ans = (n * (l % 9) % 9 + n * (n - 1) % 9 * 5 % 9) % 9;
1 |
|
如有疑问,可以在下方评论区留言
网络流算法相关模板,讲解__以后再说吧__,咕咕咕
emmm,今天开始从2018向前做NOIp的真题,并写一些题解,太蒻了Orz
n, m, q
点数、边数、问题数x, y
需要合并的两个数ufs[]
并查集find(int)
查找并查集中一个数的祖先unionn(int, int)
合并两个数所在集合
1 | const int maxn = 10010; |
1 | template <typename T> |
1 | template <typename T> |
vector<数据类型> 名;
例 vector<int> a;
a.size();
读取大小a.resize();
改变大小a.push_back(x);
尾部添加元素xa.pop_back();
删除最后一个元素a.clear();
清空a.empty()
询问是否为空(bool类型)a[]
访问元素(可修改)
头文件: #include <queue>
参数: priority_queue<Type, Container, Functional>
Type
数据类型 不可省
Container
容器(vector,deque)默认vector
Functional
比较方式,默认operator <
大根堆
与queue类似
priority_queue<int, vector<int>, greater<int> > q;
使用仿函数greater<>
1 | struct Node |
1 | bool operator < (Node a, Node b) |
x值大的优先级低,排在队前
x相等,y大的优先级低
1 | struct cmp |
有 $n$ 件物品,和一容积为 $V$ 的背包,第 $i$ 件物品的体积为 $w_i$ ,价值为 $c_i$ 。将第几件物品装入,使体积不超过总体积,且价值和最大,求最大价值。
由题意易知状态转移方程: $F_{i,j} = max(F_{i-1,j}\ , F_{i-1,j-w_i} + c_i)$
$F_{i, j}$ 为前 $i$ 件物品放入容量为 $V$ 的背包中最大价值
时间复杂度 $O(n\times V)$ ,空间复杂度 $O(n\times V)$
注意倒序,保证f[n][V]
为结果
1 | for (int i = 1; i <= n; ++i) |
降至一维数组
时间复杂度 $O(n\times V)$ ,空间复杂度 $O(V)$
1 | for (int i = 1; i <= n; ++i) |
有 $n$ 种物品(每种 无限件 ),和一容积为 $V$ 的背包,第 $i$ 种物品的体积为 $w_i$ ,价值为 $c_i$ 。将第几种物品取任意件装入,使体积不超过总体积,且价值和最大,求最大价值。
将01背包第二个循环改为正序即可
状态转移方程:$F_j = max(F_j\ , F_{j-w_i}+c_i)$
1 | for (int i = 1; i <= n; ++i) |
有 $N$ 种物品,和一容积为 $V$ 的背包,第 $i$ 种物品有 $n_i$ 件,体积为 $w_i$ ,价值为 $c_i$ 。将第几件物品装入,使体积不超过总体积,且价值和最大,求最大价值。
状态转移方程:$F_{i,v} = max(F_{i-1,v-k\times w_i} + k\times c_i | 0\leqslant k\leqslant n_i)$
时间复杂度:$O(V\times \sum{n_i})$
1 | for (int i = 1; i <= N; ++i) |
把 $n_i$ 件一种物品化为单独的 $n_i$ 件物品即可
时间复杂度:$O(V\times \sum{n_i})$
框架略
$$
n_i\to 1+2+4+\dots +2^{k-1}+\dots +(n_i-2^k+1)
$$
$$
\sum{n_i}\to \sum{\log_2{n_i}}
$$
时间复杂度:$O(V\times \sum{\log_2{n_i}})$
1 | for (int i = 1; i <= n; ++i) |
有 $N$ 种物品,和一容积为 $V$ 的背包,第 $i$ 种物品有 $n_i$ 件或无穷件,体积为 $w_i$ ,价值为 $c_i$ 。将第几件物品装入,使体积不超过总体积,且价值和最大,求最大价值。
1 | for (int i = 1; i <= N; ++i) |
有 $N$ 件物品,容积为 $V,U$ 的两个背包,每件物品有两种费用,选择物品需要付出两种代价,第 $i$ 件代价为 $a_i,b_i$,价值为 $c_i$。将第几件物品装入,使体积不超过总体积,且价值和最大,求最大价值。
改为二维数组即可
状态转移方程:$F_{v,u} = max(F_{v,u}\ , F_{v-a_i,u-b_i} + c_i)$
$F_{v,u}$ 表示前面的物品付出代价分别为 $v,u$ 时的最大价值
框架略
循环顺序
v = V..0 u = U..0
v = 0..V u = 0..U
有 $K$ 组物品, $V$ 的背包,第 $k$ 组有 $N_k$ 件物品,第 $i$ 件物品的体积为 $w_i$ ,价值为 $c_i$ ,每组中只能选一件物品。将第几件物品装入,使体积不超过总体积,且价值和最大,求最大价值。
1 | for (int k = 1; k <= K; ++k) |
状态转移方程:$F_{i,v} = sum(F_{i-1,v}, F_{i-1,v-w_i})\ \ \ (F_{0,0} = 1)$
1 | f[0] = 1; |
heap[]
堆heap_size
堆大小put(int)
压入一个数get()
弹出堆顶
1 | int heap[maxn]; |
1 | int heap[maxn]; |
n, m, s
点数、边数、源点cnt, head[], edge[], add(int, int, int)
链式前向星dist[]
各点到源点路径长vis[]
记录
1 | const int maxn = 10010; |
n, m, _map[][]
点数、边数、邻接矩阵dist[]
树根到各点路径长pre[]
生成树路径
1 | const int maxn = 101; |
ufs[], find(int), unionn(int, int)
并查集结构edge[]
链式前向星cmp(Edge, Edge)
边排序方案
1 | const int maxn = 1010; |
例:洛谷P3375
pre()
求前缀数组kmp()
匹配字符串
1 | char s1[1000010], s2[1000010]; |
例:洛谷P4305
hash[]
哈希表find(int x)
查找哈希表中 $x$ 的位置push(int x)
将 $x$ 插入到哈希表中check(int x)
查找 $x$ 是否在哈希表中
1 |
|
例:洛谷P3370
1 | typedef unsigned long long ULL; |
1 | typedef unsigned long long ULL; |
1 | typedef unsigned long long ULL; |
1 | typedef unsigned long long ULL; |
n, m, G[][]
点数、边数、邻接矩阵dist[][]
每对顶点间路径长度pre[][]
每对顶点之间路径make()
建图
1 | const int maxn = 110; |