《遗经》(退役后我遗留下来的我的经验)
记:
下面是我从初三开始做的经验总结,也是我学 OI 以来 \(90.114514\%\) 的思想和坑,虽然我靠这些思想直接退役了,但是我都写了就放一下吧。
高一进行了去shi,但是保留了一部分初三原本的味道。
在高二暑假期间重编排了一下。
又在退役后删除了一点无内涵的文字并公开。
几乎是每次遇到难处我都会把自己的感悟放在这篇文章,所以尽管最近是高二暑假期间重排,但是 4 个月的填补后仍然混乱。
如果真的阅读的话,有的条我直接靠意识写的 可以当他不存在。
温馨提示:本篇文章没有被列入四书五经中的五经之中,五经包含《诗经》《尚书》《礼记》《周易》《春秋》,想看五经的同学不要走错了。毕竟五经是儒家的,我觉得道家币儒家厉害,《遗经》自然是随我——也是道家的。
下面是正文
文件夹名称是准考证号!
心态
NOIP
心静着推前两个题(不难),注意此时不要浪费时间、瞎想东西
情况一、还剩 2.5 h
15 min 读完题
15 min 推点 T3、T4(未到非人难度) 小性质,并由此判断出哪个题可做。
如果都不可做就拼部分分,手速,拼好了就写拍子 or 自信眼观察。
如果有可做的就先想 0.5 h,然后去写另一个题的暴力,再想 0.5 h,最后狂码。
情况一、还剩 1.5 h
在思考前两题心乱时理应读完题
直接开始拼部分分,手速,拼好了肉眼检查。
除了唐人暴力也许剩下 75min,这时再冷静 40min 思考一些更牛部分分,最后半小时狂码。
要相信自己,一份普通代码不过只是 15+20 min,唐人代码不过 3~10 min。
NOI(V)P
开始 15min 先看懂四道题题面,把第一印象的思路和算法写下来,把可做的部分分记下来,作为考试中可选择的方向。
考试中一定不要瞎想别的东西,全神贯注投入考试。
T1 是必刷题,可以先推 5min 小性质结论,再找点、捏点样例手玩 5min,中间把本题一定会用到的结论整理出来。
第一题不会太麻烦,如果感觉自己很偏一定要检查目前思路的正确性,如果不对及时换,不能浪费太长时间。
同时不要无缘无故否认一些思路,你要去想再去否认。
T2、T3、T4 应该有一道看起来可做的:
首先都应该猜点那题的性质性质,并证明一些,有用的用来做题。
-
感觉是转化题意的题:我们可以试图去思考一下,猜一些结论,把题面猜地越简单越好,反正你能检查,怕什么?。
注意尽量避免使用代码打表,因为很费时间(代码 + 观察时间)。
转化完基本可以写一些高分部分分,如果新题意可做可以考虑加上 DP 之类冲正解。 -
感觉是可做的数据结构的题:这种一般部分分可以想一下,比如套个分块、莫队、整体二分弄点高分部分分。
-
感觉是可做的 DP 题:先大胆猜写一下 DP 式子的样子,胡乱写一些 DP 数组含义,看一下能不能用,找到能用且有点希望的就考虑如何维护(可用容斥之类)。
这时可以写一些部分分了。
转移式子直接大胆写,写完再证。
优化复杂度可以试图去掉一维(用容斥)。(bool DP 可用 bitset 优化)
当然优化与写 DP 都需要推点小结论性质。 -
感觉是可做的组合数学题:先大胆猜写 DP 式子的样子,然后思考容斥去掉贡献,遇到算重可以想一下二项式反演 -1 直接放到那个 DP 数组上,不用保证中间的 DP 含义,保证最后的 ans 就好了。
搜索:
别忘了剪枝、折半。
DP
- 确定好数组含义,别自以为是。
- 可以从增量的角度看。
- 打表决策点单调性
构造题:
- 猜规律打表
- 猜结论
- 抽屉原理
- 直接想点松的限制能凑出来就是对的,别想太优的。
- 我们可以定义几个很牛王的操作然后使用。
思维
-
正难则反
-
特殊的性质一定要看出含义。
-
思路都写下来别忘了
-
大胆猜结论
-
% 与余数或者拆式子有关
-
有方格的题,不要被误导,也可以转化为任意图。
-
把题想简单点。
-
可离线就是可离线
-
一题多问不要害怕,要想着先做一个,有的不可以综合做出来,反而是一个出来了,别的同理。
-
把题面用简单的语言描述一下——(数学语言,人类语言,图论语言)。
-
题目某些限制给的很简单,直接大胆猜结论就行,比如贪心选择。
-
一些最值问题可以二分,一些有些复杂的拓展问题也可以二分,甚至二分套二分。
-
看似很复杂的题可能是很多情况冗杂在一起,我们只需要分开几种情况题目就变得很简单了。
-
可以看是否有单调性质,找临界。
-
有奇怪操作的,可能它不会操作很多次,可能是 1 or 2。
-
可以大胆猜一些能让题变简单的性质,你只需要慢慢 check 结论是否对(感性即可)。
-
充分不会,可以去弄必要。
-
如果遇到一些答案很少的数,可以直接把所有可能的数都存下来,然后暴力判断是否算重或者合法。
-
想题不用直接冲正解,从弱化问题入手,从稍劣的复杂度入手,正解可能就在其中。
-
很独立的 DP 式子分开转移(左右脚)。
-
一些离答案很近的题,可以枚举前 10 个,可以拿很多分。
-
考试中途如果很迷糊开始走神,你应该立刻去洗脸,镇静自己,相信肯定有自己能拿到的分不能直接放弃。
-
无包含关系 <=> 左右端点递增
-
一些类似数位题、状态之间互相限制的题可以把状态跑下来,也许很小可以直接写。
-
区间 LCA 的深度为:\(min_{l≤i≤r}dep[LCA(i,i+1)]\)
-
整体 \(+1\) 在 01trie 上表现为从后往前建树 + 一直递归 0 节点交换左右儿子。
-
直接猜测决策单调性,验证是否四边形不等式优化 DP 把转移点打表出来看是否有单调性。
-
butset._Find_first()第一个 true 下标、bitset.filp()翻转 -
猜算法+猜结论。
-
路径或连通不只是点分治,或者重新计算会爆(撤销不行)可以线段树分治。
-
直径定理:两个连通块合起来直径只在四点之中。
-
变化值很少分块抽屉原理,还有一些看似无意义的大于关系也有可能是抽屉原理。
-
对于要求值相等的 DP 题,我们可以开一维表示差值。
-
\(f_{i,j}=f_{i-1,j}/f_{i,j-1}\) 类型的,我们发现随便一个就可以转移好,所以可以选择你觉得好的转移。(如和 65 一样的状态,我们从 \(i-1\) 转移第三维会增,反之则降,所以我们可以通过选择把第三维控制在一个很小的值域里,这样很好!)
-
切比雪夫距离和曼哈顿距离可以互转。曼哈顿距离和可以分开计算,而切比雪夫距离定下来的范围为矩形。
-
可以从组合数的题组合意义思考来做计数题。
-
(a_i+a_j,b_i+b_j) 可以转化为 (-a_i,-b_i)、(a_j,b_j)。
-
有关最短路与边修改等问题可以直接建最短路树,性质是到根节点走树边最好,走非树边只是为了连通。非树边有个路径 min 的 trick。
-
很重要的小性质:最值一定作为左右端点,且分块越多越优,那么我们每种数扫一遍是 \(O(n)\),我们扫前根号个,后根号个……。(CF1768F)
-
对于距离平方的增长如何判断最远长度:\(a_id^2\le nd => d\le n/a_i\)。
-
区间修改别忘了差分,DP 中也可以差分,如果是填表写法要在用他时前缀和解差分。
-
一些题我们不用他给我们的视角,我们可以换个角度,在找角度时我们可以充分与必要间互相转化,倒着考虑,比如插入操作求合法串变为验证一个串是否合法,然后增量拼凑最终取匹配了 \(n\) 位的值——知道了此类我们可以转化问题,设计 DP。
-
DP 状态只需要存下转移需要的参数就可以,到时候要枚举,但是记参数有重 or 漏问题,这个我们一定要严格等于 DP 含义,不要出现偏序 DP 含义的转移式子,比如与原串匹配了几位,这个我们必须严格遵从,枚举的东西如果能拼上我们一定要记录在对应的下标。同时保证严格遵从的同时,我们也许会出现一些违背祖宗的情况,匹配了多位但是一个操作使其大变,这时候我们可以用反悔的思想,为了保证严格遵从,我们找到这个操作影响不到的最后一个位
置,从这里转移过来! -
遇到最大值有关的,可以考虑笛卡尔树、克鲁斯卡尔重构树。
-
mex 有关的前缀覆盖问题,我们可以从当前覆盖区间增量来考虑,按值域扫,发现增量一种值如果在范围里会扩大他长度的区间,不断扩大区间,增长速度斐波那契,近 log。
-
注意类似可达性即不同区间有交集类的信息不可直接加法合并,如果最后合并仍然是连续区间可记录左右端点,不要以为在 DAG 上你就无敌了。
-
注意题目给你链 \(≠\) \(i→i+1\)
-
不等式列出来很多一定要消去合并化简,不然没法用一些扫描线之类的,你可以凭感觉写然后检验是否正确,这个是比较快的。
-
\(\begin{aligned}\sum ^{k}_{i=0}C_{k}^{i}\left( -1\right) ^{i}\\ \end{aligned}=0[k!=0]\)
-
数形结合,这种情况基本上式子有特别逆天的性质(如大量冗杂信息 = 0,导致根本不用管),直接自信使用就完事了。
-
有的需要从叶子节点开始拼路径的,我们要选择一个非叶子节点作为根便利,因为叶子节点我们特殊赋值了,而我们根节点要避嫌。
-
配合图论的题 n 点 n 边类的信息很重要,一定要观察出来这个性质。
-
一些 T or F 的可行性问题,我们可以直接代数检验,不需要什么判奇环什么乱七八糟的。
-
dp 的题不对就重写一遍 DP 式子。
-
对于离散化 DP 题,我们要给选择区间左右端点都离散化,因为他对应选 or 不选之抉择。
-
枚举起点的环形 DP 其实就是 2n 的破环成链。
-
+=string 拼接,不然单次 \(O(n)\) 的。 -
无正确性贪心 + 无复杂度乱搞 = 能过 = 正解。
-
如果想要维护 n 个信息可以尝试哈希和。
-
维护出度不好,可以权值下放维护入度,尤其那种和度数有关的操作题。
-
对于图上要求的中转点我们可以枚举,然后别的再做一些小巧处理。
-
\(x^k\) 我们不一定要枚举 \(x^k\) 和 \(k\),可以枚举 \(x\) 和 \(k\)。
-
无向图锁完点是树,有向图是 DAG
-
while ((double)clock()/CLOCKS_PER_SEC<MAX_TIME) 模拟退火();救赎之道,就在其中 -
有的题单位矩阵需要自己构建
-
写点出题人想不到但是随机数据卡到的概率较小的乱搞即可。
-
线段树维护两个标记,我们可以先在修改时处理掉一个先后关系,然后再在 pushdown 里再处理一个先后关系就好了。
-
一些枚举的题我们可以转化成简化问题 + 分治。
-
计数题我们可以数形结合(画表格,每行每列之类的)
-
优化 DP 我们可以去掉无关紧要的状态,如把两维变成一维的差值。
-
推式子遇到什么小心谨慎(下取整)之类的符号不用为难自己,大胆往下推,最后自己判对错就好了。
-
DP 时,一个东西很难 check,我们可以直接把不重要的东西用 “…” 代替,比如 \(l_1…r_1l_2…r_2\),构造出合法解的特征,关心 \(l,r\) 用他们存状态转移。
-
强制在线的题别忘了强制在线啊!
-
我们在树上有关距离的式子可以转化为深度的式子,这样好维护。
-
树重心的性质:按 dfn 序拍成序列,\(n/2\) 一定在重心的子树内,重心一定在 \(n/2\) 到根路径上。拓展:带权重心在带权中位数到根路径上。
-
平衡树节点存区间,需要删除一段区间,先把完全包含的删掉,然后不完全包含需要分裂的两个区间,我们给他先删掉,处理好再加进来就可以了。(但是一般正常出题人这种类型的题是可以用动态开点线段树做的……
-
证明自己的算法是对的可以画图感性理解。
-
可以把很多 123456789 的题先解决 01,然后用启发后用什么别的(如分治)
-
TLE 可以想一下多测清空。
-
树上背包枚举 w 时一定处理好上下界,不然复杂度会错误,实在不行就使用刷表法。
-
一些拆位 + \(\sum\) 的题考虑很多进位时,我们可以前缀和后一次借位表示。
-
线段树合并查询时不要查询到 \(l=r\) 查询到最后一个节点就截止,不然到空节点你不炸了?
-
化式子的时候可以交换两个 \(\sum\) 的位置然后用二项式定理等东西。
-
有些题感觉无从下手,可以手模样例,看看人脑如何解决,然后模拟人脑的操作,这时会发现一些性质,尤其是诈骗题时
-
任何范围的 \(\sum\) 都可以表示成前缀和,二维也可以。
-
注意如果幂次为负数需要特判再用快速幂。
-
分块 \(O(\sqrt n)\) 修改 \(O(1)\) 查询可以用 st 表存信息,时间复杂度证明修改 st 表是 \(O(\sqrt n)\) 的。
-
sort 不要排特殊点,因为它会把相同的数的顺序随机打乱。
-
对于一些合并的题,我们可以定一维 DP 表示左右端点,然后 \(f_j=f_i+1\)。
-
少用 define,因为你传参不加括号,如果穿 \(x-1\),后面还有乘法你就炸了。
-
费用流有负边权最后判断为
dis[t]!=-inf。 -
有 gcd 的式子题可以令 \(d=gcd(a,b),a=dA,b=dB\),同时在有整除号时可以去掉无用项:\(A+B|Bd,gcd(A,B)=1 => A+B|d\)
-
可以试试手玩。
-
对于有用的状态数很少的 DP,我们可以分讨一下,然后每次把有用的状态跑下来存 vector 里转移。
-
尤其根号重构,一些局部变量别忘了开 ull。
-
遇到感觉是 DP 的题,先硬设个暴力 DP,不管时间复杂度把能实现的都实现了,谁阻挡就把谁塞状态里,有的题就是考 DP 的实现,把暴力 DP 设出来就 A 了。
-
5e4 说明是根号(根号重构之类)。
-
最后取 max 之类的,我们可以打暴力看最优决策点找规律(不只是 DP 题,数学题也有这样的)。(然后也许可以建成树
-
时刻要有爆标的信心!
-
在本地跑特别慢但是复杂度对的时候,一定要在本地搞快点,可能是封装传参慢之类的,不然过不了题。
-
开 long long 的时候不仅看数组还要看函数,尤其快读快写。
-
整体二分及分治等递归的时候,一些非数组最好定局部变量,有时候你发现灵异现象大概就是全局变量混用的结果。
-
整体二分的锅:
cnt1,cnt2定全局变量。写法问题:把 mid+1 放进去后,如果可以达成条件,那么塞右边,否则塞左边。还有如果答案不具备直接减性,那么我们就移动指针修改数据结构。 -
有时候可以试着刷表改填表 or 填表改刷表,然后观察如何贡献,好的贡献方式可以预处理,不好的就只能暴力。哎……
-
注意 1GB 这种类型的题别吝啬空间去开 map,unordered map 很容易 TLE 啊!1e8 开 int 就行了。
-
可以用 bitset 位运算找 a-b=x,a+b=x 是否存在。
-
可以先极简化题意再开始做。
-
及时捋思路。
-
注意不要开 1e6 的局部变量,最好都开全局变量。
-
一定认真检查可能爆 ll 和 int128 的地方,别草草了事。
-
使用链式前向星一定要清空 head 啊!
-
遇到题目长的题我们要多读题面,注意题面中重复使用的信息(例如 R 轮数隐藏的单调性)
-
有的多组询问的题,其实可以把全局答案数组处理出来输出。
-
一些看似 n^2 区间的题目实际上可以通过单调性记录最牛的一个。比如对每个左端点记录最牛的右端点。
-
一些不知道策略顺序无从下手的基本上是 DP 题。
-
其实很多你看似很复杂的变化是很多简单情况杂糅在一起,我们把情况分开就了然了。
-
题目都比较可做实际上,别想复杂了。
-
一些 \(m^k\) 的形式可以用二项式定理凑。
-
一些 \(n×m\le 5e5\) 的题可以数据点分治。
-
简单容斥:\(合法-不合法\) 真不要忘了啊!
-
想到多个优秀的做法一定要选一个跑得快的别选好写的。
-
判断 \([l,r]\) 内任意 \(a_i=a_{i+len}\) 我们只需要比较 \([l,r-len]\) 和 \([l+len,r]\) 是否相等即可。
-
双哈希一个自然溢出一个取模就可以,全自然溢出可能会被卡。
-
一些 DP 时的限制可以转成图上走网格问题。
-
对于一些计数题我们可以猜测他的式子长什么样子,然后写一些标准的式子测一下对不对。
-
对于一些入边出边之类的题一般会出现关键点 \(\ge 3\) 的复杂部分为 \(0\) 的情况,可以从一个点的三个子树内均有关键点的情况考虑,会发现这是 \(0\)。
-
有种偏序的题,有时答案会取到不该在这里的值但是没关系因为答案最后会被更优的他该取到的值覆盖,所以不用管,大胆写就好了。
-
对于关系式子比较复杂的,我们可以分情况跑,这样可以降低复杂度,如树上查询,直接把三位偏序转为二维偏序。
-
没思路就多读几遍题目。
-
就算正解想不出来打部分分也可以很高的啊!不要气馁啊。
-
一些题我们可以想一下随机数据下怎么做,可以先写上去。
-
注意算复杂度不要忘记 T(多组数据的常数)
-
考试不要慌张,你不会的题会的人也不多。
-
使得 \(\sum c_ip_i\) 增加得最少且任意修改 \(p_i\),则增加 \(gcd_i\{c_i\}\)。
-
能奇偶性的题就是能奇偶性,看到题第一眼就要开始化成 0、1 问题。
-
输出有误可以看一下是不是自己 RE 了,不要一直检查代码正确性。
-
大胆贪心大胆写,大胆搜索大胆写。
-
用 map 的时候一定要
count()判断一下有没有,不然会插入一个 \({hash,0}\) 常数爆炸。 -
看到 \(\sum \le\) 也要想一下是不是长度种类很少。
-
有时候两个哈希要用 pair<> 的时候其实可以把两个哈希值随便乘个数加起来就可以用一个哈希值了,直接用 unorderedmap 就可以了。
-
不要嫌麻烦用 cin,cout 啊!
-
有关二进制的 DP 我们可以思考是否与位数无关,不关心从左往右一个一个填。所以直接把位数作为一维,把当前位数的 1 作为一维,剩下的就不多说了。
-
写一些类似括号匹配等题的哈希的时候,注意哈希值不要定全局的要 1~n+1 都随一个哈希值,如果 1++……+++%^@#&$#@=n+1 的话就会出现没有括号匹配但是计入答案的情况。
-
在一些图上边权保留之类的题可以思考克鲁斯卡尔重构树
-
一些 DP 题如果发现不合法状态可以求,可以容斥来方便计算。然后计数不合法状态的时候作为一个新问题,把 \(a_i=a_{i+1}\) 作为一段后 \(f_i=f_j+c(j+1,i)\) 这样转移即可,我们容斥只关心奇偶性所以只需要记录一维段数奇偶就好。
-
至少 -> 恰好 不一定二项式反演,也可以至少 i - 恰好 i+1~n 的加法容斥。
-
如果模数 > n,那么不可以直接使用组合数(会不小心变成 0),需要用卢卡斯定理(一定注意不要被坑啊!)。
-
记忆化搜索不要可行性剪枝。
-
一些 \(n^2\) 暴力枚举 break 可以从中间开始枚举。
-
一些没有模数的 \(a^x\) 可以直接一个一个乘,到了 inf 就 break。
-
一些要求求很多情况的方案但是不能算重的时候可以大胆猜测这几种情况重合的方案很少且特殊。
-
哈希忒波u永远的神!
#include<ext/pb_ds/assoc_container.hpp>
__gnu_pbds::gp_hash_table<ull,int> dy;
-
暴力枚举的时候,如果发现当前节点开始绝对不可能成为最优解就不要枚举,比如 i 开始枚举时不要选 i-1 的数,否则不如从 i-1 开始。这样的话一些题可以从 \(n^2\) 直接降到 \(n\),证明不多说。
-
线段树合并的锅:懒标记永久化的时候合并和修改的时候注意下传懒标记,然后把经过的节点懒标记清零,注意
-
思路一定要写在纸上不要写在电脑上。
-
注意线段树区间查询的时候不要脱出 [1,n],不然 l>=L,r<=R 判断不到。
-
别忘了卡常(排序、break 不要因为美观就处理冗杂信息)(尤其很抽象的复杂度 \(log^3\))。
-
初始化和多测清空。
-
涉及取等之类题目细节别忘了,写在代码注释里。
-
long long __int128 刺客要注意。
-
用 pop() 的时候 别同时用 size
-
别一个变量自己踩自己,然后乱了都
-
全局定一个变量,递归时用的时候要处理好,不然会有剩余。
-
注意数组别开小了!(动态开点)(还有一些图论题要按边的数量开,还要注意双向边之类的)
-
deque 你别在空时用 push_front
-
注意别在一些奇怪的地方存东西(树剖 siz[0] 存很大导致 son=0 ,然后分数就跟暴力一样)
-
写线段树的时候,懒标记多个互相打的可以分开下传(覆盖和加,要先下传加)
-
把很多一样的元素压进 vector 时一定不要把一样的元素处理两遍,尤其点分治。
-
点分治抛去子树贡献时注意重心的处理。
-
map 的最后一位是无限的,用的时候别搞混。
-
注意 QAQ 开到 1e5+7 而不是 1e5。
-
记得找时间检查代码的重要部分。
-
写哈希有时间卡卡,写个双哈希也可以。
-
只要输入大于 10000 就写快读。
-
树上 k 级祖先一定要判断 k=0 的情况。
-
本地一定要开大栈空间
-
平衡树查询时要下发懒标记。
-
有减法取模一定要注意
-
bitset cin 输入是倒着的(左右移也是)
-
如果想要每 len 个分一个块,那么
kuai[i]=(i-1)/len,在块的第 i%len 个位置。 -
wqs 二分恰好 k 条边左边界为 -inf,不是恰好左边界定 0。
-
分块插入元素调整块长,把当前多的元素分到后面的块,一直分分分到最后,最后多了可以开新块。如果紧接着有删除操作就不用了。
-
不要定义 y0,y1,yn,j0,j1,jn 等全局变量。
-
重剖跳 LCA 是链顶的深度而不是当前节点的深度。
-
注意如果是二叉树结构
(p<<1)这么写,并在p>nbreak会导致一下子越界了,所以开两倍。 -
注意尤其数据结构累和类的可能会炸 long long 要开 int128
-
复制暴力代码的时候没改倍增上界。

浙公网安备 33010602011771号