暑假清北学堂集训笔记
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了暑假清北学堂集训笔记相关的知识,希望对你有一定的参考价值。
day -1
订票订得晚只好坐凌晨1点的火车……
day 0
7点钟到北京了,坐滴滴到酒店,然后去华北电力大学报道,路上看到一辆共享单车,弄了大半天才发现是坏的。。。
报完到就在旁边的餐厅吃了起来。
day 1
南小鸟(钟皓曦)讲 搜索 分治 倍增 贪心
ST表: f[i][j]表示 从i到i+2^j-1这2^j个位置的元素最大值 初始化: f[i][0]=z[i] 转移: f[i][j]=max(f[i][j-1],f[i+2^(j-1)][j-1])
LCA(最近公公祖先):f[i][j] 表示从树上编号为i的点向上走2^j步会走到哪个点 初始化: f[i][0]=father[i] 转移: f[i][j]=f[f[i][j-1][j-1]
求a,b,LCA时将a置为深度深的那个点,然后一直往上走,知道两个点深度相同,再将两个点同时向上走,走到同一个点时,那个点就是他们的LCA
inline void dfs(int now,int f) { for (unsigned i = 0;i < edges[now].size();i++) if (!deep[edges[now][i]] && edges[now][i] != f) { deep[edges[now][i]] = deep[now]+1; father[edges[now][i]][0] = now; dfs(edges[now][i],now); } } void init() { for (int j = 1;(1<<j) <= n;j++) for (int i = 1;i <= n;i++) if (father[i][j-1] != -1) father[i][j] = father[father[i][j-1]][j-1]; } inline int lca(int a,int b) { if (deep[a] < deep[b]) swap(a,b); int i; for (i = 0;(1<<i) <= deep[a];i++); i--; for (int j = i;j >= 0;j--) if (deep[a]-(1<<j) >= deep[b]) a = father[a][j]; if (a == b) return a; for (int j = i;j >= 0;j--) { if (father[a][j] != -1 && father[a][j] != father[b][j]) { a = father[a][j]; b = father[b][j]; } } return father[a][0]; }
快速幂:快速幂是倍增和分治的结合,如:2^50可以分为(2^25)^2 2^25又可以分为(2^12)^2*2一直这样,我们就可以在O(log n)时间内求出x^n
inline int QuickPow(int x,int y) { if (y == 1) return x; int z = QuickPow(x,y>>1); if (y&1) return z*z*x%mod; return z*z%mod; }
二分查找:二分查找可以在一个单调的序列中用O(log n)的时间找出一个数,它是一种分治
inline int find(int l,int r,int x) { if (r == l) return l; int mid = l+r>>1; if (x < a[mid]) return find(l,mid); return find(mid,r); }
贪心:贪心一般形式是,以某种方式将所有物品排序,排序后按照从小到大进行选择
搜索:dfs,bfs
搜索优化:
剪枝:把不优于当前最优解的状态剪掉
卡时:卡时是一种骗分技巧,一般用于最优性问题,当程序准备超时时,直接输出当前答案,然后结束程序
#include <cstdlib> #include <cstdio> #include <ctime> int t,ans; inline void dfs(...) { if (clock-t >= 990) { printf("%d",ans); exit(0); } ... } int main() { t = clock(); ... dfs(...); printf("%d",ans); return 0; }
晚上测试
第一题是一题不可做的模拟题!!!
我写里1.5h+
结果还是没能调出来
第二题写了一个四重循环加卡时
第三题没看
结果
……
0+0+0=0
爆零啦!!!!!!!!!!!!! 有大佬200 Orz %%%
day 2
一上午都在讲数论,作为五年级小学生表示听不懂!!!!!!!!!!!!!!!!!!!
中午南小鸟走了,杨乐来了
杨乐讲了一些背包和记忆化搜索
day 3
上午,杨乐又讲了一些线性dp
LIS:最长不下降子序列
假设我们需要求以x结尾的最长下降子序列dp[x],由最忧性可得,我们除去最后一个位置(也就是x),还是一段最长下降,
那我们可以枚举这个子序列的结尾y,最优值就是dp[y]。但需要注意的是,必须保证A[x] < A[Y], x比 Y要低,才满足下降的要求。
我们从所有枚举的结果中找到一个最大的即可。
转移方程:dp[i] = max{dp[j]+1} (j<i a[i]<a[j])
LCS:最长公共子序列
假设我们需要求两个序列分别以i,j结尾的最长公共子序列
dp[i][j], 接下来我们可以分几种情况讨论:
a[i]不在公共子序列中,那么长度则等于dp[i-1][j]
b[j]不在公共子序列中,那么长度则等于dp[i][j-1]
a[i]与b[j]都在子序列中,并且两者匹配,那么长度等于dp[i-1][j-1]+1
然后还讲了区间dp,二维平面dp,状态划分dp
下午杨乐又讲了序列划分dp,树形dp,状态压缩dp……
day 4
杨乐也走了,黄致焕来了
黄致焕讲了栈,单调栈,队列,单调队列
day4就这样愉快的结束了
day 5
黄致焕又讲了并查集,堆,可并堆,树状数组,左偏树等离奇数据结构。。。
并查集:
并查集是一种树形数据结构支持合并,查找祖先
查找如下:
inline int find(int x) { //father[x]表示x的祖先,father[x]=x表示x是根节点 if (father[x] == x) return x; //找到根节点 return father[x] = find(father[x]); //祖先的祖先就是我的祖先 }
合并如下:
inline void Union(int x,int y) { father[find(x)] = find(y); } //合并祖先
堆:
定义:一棵满足以下两个性质的二叉树:
1.父节点权值大于等于(大根堆)或小于等于(小根堆)任何一个儿子的权值。
2.每个节点的左子树和右子树都是一个堆。
左偏树:
左偏树是可并堆的一种
在左偏树中,每个节点包含两个属性:权值和距离(dist)。除了之前二叉堆支持的操作以外,左偏树还支持合并(merge)操作。
左偏树的每个节点都满足做儿子的dist大于右儿子的dist,每个节点的dist的值即为该子树中与该节点最近的点的距离。
合并如下:
inline int merge(int x,int y) { if (!x || !y) return x|y; //判断空树 if (heap[x].key < heap[y].key) swap(x,y); //让键值大的为x heap[x].rson = merge(y,heap[x].rson); //将右儿子与y合并 if (heap[heap[x].lson].dist < heap[heap[x].rson].dist) swap(heap[x].lson,heap[x].rson); //让dist大的为左儿子 heap[x].dist = heap[heap[x].rson].dist+1; //算dist return x; }
删除如下:
inline int del(int x) { return merge(heap[x].lson,heap[x].rson); } //将左右儿子合并
然后老师又讲了很迷很迷的一些数据结构……
day 6
姜志豪来了,图论也来啦
树的遍历
BFS:一开始队列中有一个点,将一个点出队,将它的子结点全都入队。
DFS:递归到一个点时,依次递归它的子结点。
最小生成树
prim:
先随机找一个点x作为根,然后维护一个集合S(存已经连通的点)和一个集合D(存当前连接S中所有点的线段,两端点都在S中的除外)
初始化S={x},D={x所连接的所有边};
每次在D中选一个权值最小的边,然后将该边删去。该边所连接的另一个点放入S中,直到S中点数=全部点数。
这里记顶点数n,边数m,
时间复杂度:O(m log n)
kruskal:
将边权从小到大排序,每次选择边权最小的,如果当前边连接的点已经连通了,就不选这条边。
利用并查集维护是否连通。
m为图中的边数
时间复杂度:O(m log m)
最短路算法
floyd:
设dist[i][j]为i~j的距离,则有动态转移方程:dist[i][j] = max{dist[i][k]+dist[k][j]}
dijkstra:
a.初始时,S只包含源点,即S={v},v的距离为0。U包含除v外的其他顶点,即:U={其余顶点},若v与U中顶点u有边,则正常有权值,若u不是v的出边邻接点,则权值为∞。
b.从U中选取一个距离v最小的顶点k,把k,加入S中(该选定的距离就是v到k的最短路径长度)。
c.以k为新考虑的中间点,修改U中各顶点的距离;若从源点v到顶点u的距离(经过顶点k)比原来距离(不经过顶点k)短,则修改顶点u的距离值,修改后的距离值的顶点k的距离加上边上的权。
d.重复步骤b和c直到所有顶点都包含在S中。
spfa:
首先建立一个数组s,s[i]代表从始点到i点所需要的最短距离。
利用一个队列进行松弛操作:
初始化s[i]=∞;
首先将始点入队,然后将始点所连接的点x入队。入队的时候,将始点到x的距离d赋值给s[i]。对于始点所连接的所有点都进行如下操作,弹出队首元素。
访问队首元素y,将队首元素y所连接的所有的点都入队。假如其中一个点为z,则判定一下s[z]是否大于s[y]+< y,z >边权。如果大于,则松弛一下,把s[y]赋值为较小的那个。
toposort:
入度:有多少条边指向他
出度:有多少条边从他发出
先统计每个点的入度,假如a->b,则in[b]++;
用栈来维护入度=0的点。
若栈非空,则在栈中弹出一个元素(并输出),然后枚举这个点能到的每一个点将它的入度-1.如果入度=0,则压入栈中。
如果没有输出所有的顶点,则有向图中一定存在环
强连通分量:
……
晚上,第二波考试
第一题:水题,n^2大暴力
第二题:不会做,仍然n^2大暴力
第三题:想到正解,写炸了!!!
100+20+30=150 有大佬270 Orz %%%
day 7
Trie树,KMP,AC自动机……
day 111
离noip还有1周……
以上是关于暑假清北学堂集训笔记的主要内容,如果未能解决你的问题,请参考以下文章