提高组大纲及模板

发布时间 2023-12-23 19:54:43作者: _wxr

https://www.noi.cn/upload/resources/file/2023/03/15/1fa58eac9c412e01ce3c89c761058a43.pdf

数据结构

  1. 线性结构
  • 【 5 】双端栈

  • 【 5 】双端队列

  • 【 5 】单调队列

  • 【 6 】优先队列

  • 【 6 】ST 表(Sparse Table)

struct sparseTable
{
	int g(int x, int y)
	{
		return std::max(x, y);
		//需满足 g(x, x) = x
	}
	
	int f[maxn][maxk], log[maxn];
	void init(int n, int a[])
	{
		for (int i = 1; i <= n; i++) log[i] = std::log2(i);
		for (int i = 1; i <= n; i++) f[i][0] = a[i];
		
		int K = std::log2(n);
		for (int j = 1; j <= K; j++)
		{
			for (int i = 1; i <= n; i++)
			{
				if (i + (1 << (j - 1)) > n) f[i][j] = f[i][j - 1];
				else f[i][j] = g(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
			}
		}
	}
	
	int query(int l, int r)
	{
		int t = log[r - l + 1];
		return g(f[l][t], f[r - (1 << t) + 1][t]);
	}
} ST;
  1. 集合与森林
  • 【 6 】并查集
struct dsu
{
	int fa[maxn], size[maxn];
	void init(int n) { for (int i = 1; i <= n; i++) fa[i] = i, size[i] = 1; }
	int getFath(int u) { return fa[u] == u ? fa[u] : fa[u] = getFath(fa[u]); }
	void follow(int u, int v)
	{
		int fu = getFath(u), fv = getFath(v);
		if (size[fu] < size[fv]) fa[fu] = fv, size[fv] += size[fu];
		else fa[fv] = fu, size[fu] += size[fv];
	}
} D;
  • 【 6 】树的孩子兄弟表示法
  1. 特殊树
  • 【 6 】二叉堆

  • 【 6 】树状数组

树状数组能做的,线段树一定能做;线段树能做的,树状数组不一定可以。

  • 【 6 】线段树
struct segmentTree
{
	struct node
	{
		int l, r;
		long long sum, tag;
	}
	T[maxn * 4];
	
	long long build(int p, int l, int r, long long a[])
	{
		T[p].l = l, T[p].r = r, T[p].tag = 0;
		if (l == r) return T[p].sum = a[l];
		else return T[p].sum = build(p << 1, l, (l + r) >> 1, a) + build((p << 1) + 1, ((l + r) >> 1) + 1, r, a);
	}
	
	void downData(int p)
	{
		T[p << 1].sum += T[p].tag * (T[p << 1].r - T[p << 1].l + 1), T[p << 1].tag += T[p].tag;
		T[(p << 1) + 1].sum += T[p].tag * (T[(p << 1) + 1].r - T[(p << 1) + 1].l + 1), T[(p << 1) + 1].tag += T[p].tag;
		T[p].tag = 0;
	}
	
	long long add(int p, int l, int r, long long k)
	{
		if (r < T[p].l || T[p].r < l) return T[p].sum;
		else if (l <= T[p].l && T[p].r <= r) return T[p].tag += k, T[p].sum += k * (T[p].r - T[p].l + 1);
		else return downData(p), T[p].sum = add(p << 1, l, r, k) + add((p << 1) + 1, l, r, k);
	}
	
	long long query(int p, int l, int r)
	{
		if (r < T[p].l || T[p].r < l) return 0;
		else if (l <= T[p].l && T[p].r <= r) return T[p].sum;
		else return downData(p), query(p << 1, l, r) + query((p << 1) + 1, l, r);
	}
}
T;
  • 【 6 】字典树(Trie 树)
struct trie
{
	struct node
	{
		int val;
		node *next[maxm];
		node()
		{
			val = 0;
			for (int i = 1; i <= 26; i++) next[i] = NULL;
		}		
	};

	node root;

	void insert(char s[], int x)
	{
		node *p = &root;
		int n = strlen(s + 1);
		for (int i = 1; i <= n; i++)
		{
			int t = s[i] - 'a' + 1;
			if (p -> next[t] == NULL) p -> next[t] = new node;
			p = p -> next[t];
		}
		p -> val = x;
	}
	
	int find(char s[])
	{
		node *p = &root;
		int n = strlen(s + 1);
		for (int i = 1; i <= n; i++)
		{
			int t = s[i] - 'a' + 1;
			if (p -> next[t] == NULL) return -1;
			else p = p -> next[t];
		}
		if (p -> val == 0) return -1;
		else return p -> val;
	}
}
T;
  • 【 7 】笛卡尔树

不会

  • 【 8 】平衡树:AVL、treap、splay 等

不会

  1. 常见图
  • 【 5 】稀疏图

  • 【 6 】偶图(二分图)

struct Hungarian
{
    int road[maxn], link[maxn], dfn;

    bool dfs(int u)
    {
        for (int j = g.Last[u], v; j != 0; j = g.Next[j])
        {
            if (road[v = g.to[j]] == dfn) continue;
            road[v] = dfn;
            if (link[v] == -1 || dfs(link[v]))
            {
                link[v] = u;
                return 1;
            }
        }
        return 0;
    }

    int getMaxMatch(int n)
    {
        int ans = 0;
        dfn = 0;
        for (int i = 1; i <= n; i++) link[i] = road[i] = -1;
        for (int i = 1; i <= n; i++) 
        {
            dfn++;
            ans += dfs(i);
        }
        return ans; 
    }
}
H;
  • 【 6 】欧拉图

  • 【 6 】有向无环图

  • 【 7 】连通图与强连通图

  • 【 7 】双连通图

  1. 哈希表
  • 【 5 】数值哈希函数构造

  • 【 6 】字符串哈希函数构造

  • 【 6 】哈希冲突的常用处理方法

算法

  1. 复杂度分析
  • 【 6 】时间复杂度分析

  • 【 6 】空间复杂度分析

  1. 算法策略
  • 【 6 】离散化
  1. 基础算法
  • 【 6 】分治算法
  1. 排序算法
  • 【 5 】归并排序

  • 【 5 】快速排序

int a[maxn], b[maxn];
void qsort(int l, int r)
{
	if (l >= r) return;
	int x = a[(l + r) >> 1];
	int i = l, j = r;
	for (int k = l; k <= r; k++)
	{
		if (a[k] < x) b[i++] = a[k];
		if (a[k] > x) b[j--] = a[k];
	}
	for (int k = l; k < i; k++) a[k] = b[k];
	for (int k = i; k <= j; k++) a[k] = x;
	for (int k = r; k > j; k--) a[k] = b[k];
	qsort(l, i - 1), qsort(j + 1, r);
	return;
}
  • 【 6 】堆排序

  • 【 5 】桶排序

  • 【 6 】基数排序

  1. 字符串相关算法
  • 【 5 】字符串匹配:KMP 算法
//不会
  1. 搜索算法
  • 【 6 】搜索的剪枝优化

  • 【 6 】记忆化搜索

  • 【 7 】启发式搜索

  • 【 7 】双向广度优先搜索

  • 【 7 】迭代加深搜索

  1. 图论算法
  • 【 6 】最小生成树:Prim 和 Kruskal 等算法

  • 【 7 】次小生成树

//不会
  • 【 6 】单源最短路:Bellman-Ford、Dijkstra、SPFA 等算法
bool mark[maxn];
long long dis[maxn];

void dijk(int n, int s)
{
	std::priority_queue< std::pair<long long, int> > q;
	for (int i = 1; i <= n; i++) mark[i] = 0;
	for (int i = 1; i <= n; i++) dis[i] = 1LL << 60;
	dis[1] = 0;
	q.push(std::make_pair(0, 1));
	while (!q.empty())
	{
		int u = q.top().second;
		q.pop();
		if (mark[u]) continue;
		mark[u] = 1;
		for (int j = g.Last[u]; j != 0; j = g.Next[j])
		{
			int v = g.to[j];
			if (mark[v] == 1) continue;
			if (dis[v] > dis[u] + g.w[j])
			{
				dis[v] = dis[u] + g.w[j];
				q.push(std::make_pair(-dis[v], v));
			}
		}
	}
	return;
}
  • 【 7 】单源次短路

  • 【 6 】Floyd-Warshall 算法

  • 【 6 】有向无环图的拓扑排序

  • 【 6 】欧拉道路和欧拉回路

  • 【 6 】二分图的判定

  • 【 7 】强连通分量

struct Tarjan
{
	int dfn[maxn], low[maxn];
	int dfnCnt;
	int scc[maxn], sccCnt;
	int stack[maxn], top;
	int mark[maxn];
	
	void dfs(int u)
	{
		if (mark[u] == 1) return;
		stack[++top] = u, mark[u] = 1;
		dfn[u] = low[u] = ++dfnCnt;
		for (int j = g.Last[u]; j != 0; j = g.Next[j])
		{
			int v = g.to[j];
			if (dfn[v] == 0) dfs(v), low[u] = std::min(low[u], low[v]);
			else if (mark[v]) low[u] = std::min(low[u], dfn[v]);
		}
		
		if (dfn[u] == low[u])
		{
			sccCnt++;
			int t;
			do
			{
				t = stack[top--];
				mark[t] = 0;
				scc[t] = sccCnt;
			}
			while(t != u);
		}
		return;
	}
	
	void getScc(int n)
	{
		dfnCnt = sccCnt = top = 0;
		for (int i = 1; i <= n; i++)
		{
			if (dfn[i] == 0)
			{
				dfnCnt = 0;
				dfs(i);
			}
		}
	}
}
T;
  • 【 7 】割点、割边

  • 【 6 】树的重心、直径、DFS 序与欧拉序

  • 【 6 】树上差分、子树和与倍增

  • 【 6 】最近公共祖先

struct LCA
{
	int fa[maxn][maxk], depth[maxn];
	int K;
	
	void init(int n, int root)
	{
		K = std::log2(n);
		dfs(root, 0);
		for (int j = 1; j <= K; j++)
		{
			for (int i = 1; i <= n; i++)
			{
				fa[i][j] = fa[fa[i][j - 1]][j - 1];
			}
		}
	}
	
	void dfs(int u, int fath)
	{
		fa[u][0] = fath, depth[u] = depth[fath] + 1;
		for (int j = g.Last[u]; j != 0; j = g.Next[j])
		{
			int v = g.to[j];
			if (v == fath) continue;
			dfs(v, u);
		}
	}
	
	int getLca(int u, int v)
	{
		if (depth[u] > depth[v]) std::swap(u, v);
		for (int i = K; i >= 0; i--)
		{
			if (depth[fa[v][i]] >= depth[u]) v = fa[v][i];
		}
		if (u == v) return u;
		for (int i = K; i >= 0; i--)
		{
			if (fa[u][i] != fa[v][i])
			{
				u = fa[u][i], v = fa[v][i];
			}
		}
		return fa[u][0];
	}
} L;
  1. 动态规划
  • 【 6 】树型动态规划

  • 【 7 】状态压缩动态规划

  • 【 8 】动态规划的常用优化

数学及其他

  1. 初等数学
  • 【 5 】代数(高中部分)

  • 【 6 】几何(高中部分)

  1. 初等数论
  • 【 5 】同余式

  • 【 7 】欧拉定理和欧拉函数

  • 【 7 】费马小定理

  • 【 7 】威尔逊定理

  • 【 7 】裴蜀定理

  • 【 7 】模运算意义下的逆元

  • 【 7 】扩展欧几里得算法

  • 【 7 】中国剩余定理

  1. 离散与组合数学
  • 【 6 】多重集合

  • 【 6 】等价类

  • 【 6 】多重集上的排列

  • 【 6 】多重集上的组合

  • 【 6 】错排列、圆排列

  • 【 6 】鸽巢原理

  • 【 6 】二项式定理

  • 【 7 】容斥原理

  • 【 7 】卡特兰(Catalan)数

  1. 线性代数
  • 【 5 】向量与矩阵的概念

  • 【 6 】向量的运算

  • 【 6 】矩阵的初等变换

  • 【 6 】矩阵的运算:加法、减法、乘法与转置

struct martix
{
	int n, m;
	long long mar[maxn][maxn];
	
	martix(int _n, int _m)
	{
		n = _n, m = _m;
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= m; j++)
				mar[i][j] = 0;
	}
	
	martix operator * (const martix &t) const
	{
		martix ans(n, t.m);
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= t.m; j++)
				for (int k = 1; k <= m; k++)
					ans.mar[i][j] = (ans.mar[i][j] + mar[i][k] * t.mar[k][j]) % mod;
		return ans;
	}
	
	martix operator ^ (long long t) const
	{
		martix ans(n, m), x(n, m);
		for (int i = 1; i <= n; i++)
			ans.mar[i][i] = 1;
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= m; j++)
				x.mar[i][j] = mar[i][j];
		while (t)
		{
			if (t & 1) ans = ans * x;
			x = x * x;
			t >>= 1;
		}
		return ans;
	}
};

  • 【 6 】特殊矩阵的概念:单位阵、三角阵、对称阵和稀疏矩阵

  • 【 7 】高斯消元法