关于考试

容易被忽略的东西(加强记忆):

  • 最最重要的:特别注意用线段树维护东西时,一定要特别考虑线段树只有一个节点时会不会出错!
  • 动态规划(或递推)(不论数据范围多大都要用DP的思想思考思考,毕竟其优化空间很大!)
  • 拆式子、化式子
  • 找规律(输入较少)
  • 矩阵快速幂(数据范围较大)
  • 网络流
  • 询问离线
  • 二分
  • (离线)分治(根号分治)
  • 线段树分治(数据范围大概在50000-100000左右)
  • 倍增(数据范围较大)
  • 分块(遇到一般数据结构不太好维护的东西)
  • 从一个点u出发随机游走回到 \(u\) 的期望步数:\(\frac{2(size[u]-1)}{deg[u]}\)
  • 一堆数,两两相乘,值为这些数和的平方减去其平方的和
  • 树上联通块数=点数-边数
  • 边点转化思想(边的贡献转化为点的贡献)
  • 二叉树中度为 \(0\) 的节点数=度为 \(2\) 的节点数 \(+1(n0=n2+1)\)
    简略证明:
    \(\because n0+n1+n2=n\quad n1+2\times n2=n-1\)
    \(\therefore n0-n2=1\)
    \(\therefore n0=n2+1\)
  • 在树上从叶子结点向上BFS一般等同于从根节点向下DFS(正如改枚举因数为倍数一样可以优化复杂度)
  • 有一个数 \(X\) ,对一堆数的全排列取模,可以考虑先对这堆数排序
  • 树上最长链(直径)的性质:将两个最长链的端点分别为 \((a,b)\)\((c,d)\) 的树上联通块接在一起形成的新的联通块的最长链一定是 \((a,b)\)\((c,d)\)\((a,c)\)\((a,d)\)\((b,c)\)\((b,d)\) 中的一个
  • \(1/1+1/2+1/3...+1/n = ln(n+1)+r\)\(r\) 是欧拉常数,\(r=0.5772156649\)
  • 最大公约数分解质因数后每个质数的指数是这一堆数的min,而最小公倍数则是max
  • 辗转相除法可以通过二进制求gcd卡常数
  • 欧拉公式:\(e^{ix}=\cos x+i\sin x\)
  • 威尔逊定理:\((p-1)! \equiv -1\pmod{p}\)
  • \(f_i\) 的生成函数 \(F(x)\) 一定满足 \(F(0)=f_0\)
  • 求与一个集合有交的集合个数可以考虑取其补集进行统计
  • 注意条件概率是这么写的:\(P(B|A)\times P(A)=P(AB)\)
  • 无向图上的问题可以考虑用最短路把其变为 DAG最短路树 进行处理!
  • 一棵树中到所有点距离最大值最小的点是直径的中点!(可以和树的直径可合并性放在一起使用)
  • 写KMP的时候一定设 \(f[1]=0,k=0,now=2\) ,具体如下:
f[1]=0;k=0;now=2;
	while(now<=m){
		if(t[now]==t[k+1]||k==0){
			if(t[now]==t[k+1])f[now]=++k;
			else f[now]=k;now++;
		}
		else k=f[k];
	}
  • 求一个序列从某个点开始的前缀/后缀最大值/最小值可以考虑单调栈 !或是求从某个点开始的上升/下降序列(每次找下一个比这个数小/大的数)也可以用单调栈!(这个思想很重要)
  • 一棵树正向或反向拓扑序数量相同(顺序颠倒)
  • \(d|\gcd(x,y)=d|x,d|y\)
  • 栈->合法括号序列->卡特兰数
  • 走折线的问题->考虑按某条直线翻折
  • \(a^2+ab+b^2\) -> \((a^2+ab+b^2)(a-b)=a^3-b^3\) 注意 \(a\)\(b\) 相等的情况(用来分离 \(a\)\(b\)
  • 一个区间一共出现了多少不同的数的一些做法:
    1.离线莫队(支持带修)
    2.离线线段树扫描(固定右端点)
    3.bitset记录

考试策略

  • 开局先打暴力,不要想着写正解,把能写的部分分都写了再说,这样就不会因为想正解时间太长导致最后时间不够写暴力时心慌了(不要随性 一定要记得!)
  • 一些看似可做的题目不一定很好做,如果很长时间都没有想出来就直接放弃,因为它真的并没有看上去那么可做
  • 如果实在题目没什么思路,就可以去打打一些看似有规律题的表,找找规律,说不定就可以乱搞一些分数甚至是做掉
  • 考试切忌猜性质!能推出来的尽量推,如果实在要猜性质的话,暴力分一定要先打上!
  • 配置C++的时候注意编译中开O2、C++11、大栈及显示最多警告信息!

部分类型题目思考方向(参考):

  • 异或问题解决方案:FWT或线性基或其它小性质
  • 子序列问题解决方法:区间/其它DP或序列自动机或直接枚举每个元素选/不选
  • 概率期望题解题思路:贝叶斯公式 or 期望的线性性 or 全概率/期望公式,也就是说可以考虑写出全期望或概率公式后再考虑化简
  • 判断树的同构方法:找出重心判断 or 类似换根DP的思想找出以任意点为根的Hash值
  • 位运算:按位考虑贡献 or 有关最高位的贪心策略(详见#1007. 「2019福建省冬令营」签到题
  • 最大权独立集=全集-最小权覆盖集=补图的最大团
  • 图的联通性:DFS树上的树边与非树边 or 并查集
  • 树上问题:考虑当前点在所处的节点向相邻的节点移动时会对答案产生什么影响(之前的动态点分治与换根DP都有类似的思想),CF上有一道Nearest Leaf也是这种思想 or 点分治
  • 概率期望DP1:当选择的代价和次数相关时,考虑两个代价之间的关系,往往会有意想不到的收获
  • 概率期望DP2:当设 \(f_i\) 表示当序列长度为 \(i\) 时的答案不好做的时候可以考虑设其为 \(i\) 转移到下一个状态 \(f_{i+1}\)\(f_{i-1}\) 的答案,然后再对 \(f\) 数组求和即可
  • 树上问题:可以考虑把点上信息转移到边上维护
  • 求一些带非常见运算符的式子的值(例如取模或开根):势能分析(开根)、找规律、拆开式子(取模)等

网络流建模的一些思路

  • 网络流INF边不仅可以代表不能割,也可以用来限制流的流动方向,还可以表示选择上的限制(如离散变量模型)(或理解为描述不合法方案)
  • 遇到最小割模型的最小点覆盖问题时,若发现元素不好分为两类,则应当注意限制条件的性质,也许因为限制条件元素可以被天然分为两类
  • 网格图如果一个格子的收益与周围的格子有关一定要考虑黑白染色!
  • 网格图上转弯有收益的,拆为横纵两点后两点之间建边
  • 染色后建模可以在一定程度上简化问题(不一定只染一次色)(网格题中用到的比较多)

思考方向

  • 一定要勤于向DP、递推、网络流这些较为灵活的东西上思考,并且对于一些题还可以建图解决(类似于网络流的方法)
  • 一种方法行不通或者不够优的时候要及时更改思路,从头再想一想,不要在一种方法上停留时间过长
  • 基环树题考虑断环解决
  • 求一些数和是某个数倍数的题放到剩余系下+卷积/矩阵乘法解决
  • 遇到求数值的题需要考虑拆式子、化式子
  • 查看两个点是否连过边可以用并查集维护
  • 对于有对序列进行奇奇怪怪的变化的题目,考虑对序列进行适当地变形(例如差分一下)
  • 树上问题如果用树链剖分做复杂度较高或是较复杂可以考虑树上前缀和(树上差分)然后用树状数组维护一下即可
  • 注意答案可二分性!
  • 做题时用到二分如果复杂度仍然不够优可以考虑整体二分
  • 考虑从数据范围较小的变量入手思考问题(好吧说得彻底一点就是考虑从任意一个变量入手思考问题)
  • 根号分治的算法也是不错的思考方向
  • 当遇到一些怪怪的题目,例如和整除与余数有关的最优性问题,或是贪心正确性不高时,DP往往是解决的利器
  • 树上询问问题没有强制在线可以考虑把询问挂在节点下面再思考(当然不是树上询问也可以这样想想)
  • 针对上一句话,对于有些修改众多且复杂不好在同一时刻全部存下来也可以考虑挂询问然后线段树维护处理(例:relief grain)
  • 针对上一句话,有些没有要求强制在线且询问之间没什么关联性(比方说没有修改)就可以考虑离线处理(好吧其实有修改也可以,但是没有修改离线做不是更方便吗)
  • 写答案式并对答案式变形再解题也是很好的思路(可以在一些答案式很明显或是最优化的东西可以写成式子的题目使用)
  • DP题考虑优化时若有两组需要满足的限制不一定要使用树套树或可持久化数据结构,也可以考虑在序列上挂链表然后再更新(具体参考#328. 「20190224模拟」全连
  • 可以用DP写的题先写出DP方程再观察特点进行优化!
  • 针对上一条的DP优化,我们可以关注DP数组值或转移点等要素的特征(例如决策单调)(打表发现)
  • 动态规划不一定要从前面的状态转移到当前状态,有时用当前状态更新后面的状态可以简化问题!(俗称“刷表”与“填表”)
  • 当DP没有明显的转移顺序时考虑从数量等其它方面入手设计状态
  • 即使数据范围不允许,也可以考虑DP,DP方程写出来后再考虑优化或找规律!(差分为零就直接插值)
  • 树形DP:1.二次扫描+换根DP 2.枚举子树DP
  • 树形DP强制某个点选/不选考虑换根DP!
  • 对全排列做DP时考虑全排列的性质,也可以考虑用康拓展开对全排列编号再DP
  • 要求数值和为某一个数的倍数的方案数放在剩余系下解决可以简化复杂度!
  • 字符串题可以考虑用线段树(线段树合并)或树链剖分或LCT维护
  • 有一坨一坨区间的问题考虑对所有区间的左/右端点进行排序处理!
  • 遇到一些限制条件可以将其转化为代数恒等式
  • 若遇到要撤销一类不可减信息,可以考虑线段树分治,或者考虑每次更改后如何快速合并

数学

  • 若有 \(i\)\(i+k\) 不好直接FFT,那么将其中一个翻转再做FFT
  • 若有 \(j\)\(i/j\) 不好直接FFT,那么将下标取原根的 \(k\) 次方再做FFT

考试技巧

  • 比赛时注意各种 找规律 奇怪暴力优化 卡常 卡时限 全都要上!在此介绍一些:
    1.unordered_set在不遍历元素的情况下速度会比set快(基于hash的实现)
    2.卡时限:clock()>=t*CLOCKS_PER_SEC,其中t为所设时限(调用ctime库)
    3.sort不要写cmp函数,直接重载比较运算符速度会比这个快!
    4.以后不要用除法运算,速度是最慢的!能乘以小数的就不要除以整数!!
    5.数组尽量不要开太大,如果实在没有办法就考虑滚动数组(数组自带常数)
    6.对于具有可加可减性的数据最好不要用区间线段树维护,树状数组常数小速度快,空间开销也很小!
    7.尽可能不要在重复调用的函数中使用memset,速度慢到无法想象
  • 写部分分:
namespace Task{
	inline void Work(){
		......
	}
}

int main(){
	Task::work();
}
posted @ 2018-12-29 22:01  ForwardFuture  阅读(172)  评论(0编辑  收藏  举报