tricks & tips 1
-
一些最短路题直接建模有一点问题的话可以考虑拆点(「JOI 2021 Final」机器人)。
-
若 DP 的时候状态太大而答案很小,可以考虑答案与状态互换(「JOI 2020 Final」集邮比赛 3)。
-
要求改变一条边的边权 / 删去一条边后求 \(1\sim n\) 的最短路长度可以考虑最短路树 / 线段树(「JOI 2020 Final」奥运公交 & 「CF1163F」Indecisive Taxi Fee)。
-
有时构造其实本质上是 DP(「JOISC 2020 Day1」建筑装饰 4)。
-
区间覆盖问题可以去掉被包含的区间后按右端点排序,然后 DP(「ARC065D」シャッフル / Shuffling)。
-
分组取 \(\max/\min\) 考虑全局 \(\max/\min\) 属于哪一组(「ARC073C」Ball Coloring)。
-
折线 DP 中拐点斜率变化多少,优先队列里就要存多少个点。
-
根号分治题卡空间可以考虑离线(「CF103D」Time to Raid Cowavans)。
-
一些与树上路径合并有关的问题可以并查集(「POJ3694」Network)。
-
括号序列常见套路:
- 计数:考虑钦定左括号与哪一个位置的右括号匹配(「CSP-S 2021」括号序列);
- 把
(看成 \(1\)、)看成 \(-1\),一个合法括号序列满足总和为 \(0\) 且前缀最小值 \(= 0\)(「CF1598F」RBS)。 - 设 \(f_{l,r}\) 为区间 \([l,r]\) 满足某种条件的方案数,那么可以根据 \(l\) 和 \(r\) 与哪一个括号匹配进行转移(3.18 T2 令人闻风丧胆的英文名称 bracket)。
-
一类贪心匹配问题,代码技巧性很大(「JOI 2019 Final」硬币收藏)。
-
DP 分类讨论一定要想清楚……有时分类讨论纯粹是想复杂了(「JOI Open 2020」发电站)。
-
每次删除一个数之后中位数位置变化量 \(\le 1\)(「AGC053B」Taking the middle)。
-
数据范围小的 DP 直接大胆设状态(「CF1606E」Arena)。
-
\(\mathcal{O}(n)\) 求解带权树的重心(「SHOI2005」树的双中心)。
-
与时间有关的题也可以想一想差分(「LOJ6346」线段树:关于时间)。
-
动态加点 LCA 用倍增(「ZJOI2012」灾难)。
-
动态插入 / 删除区间 \(\rightarrow\) set(「APIO2009」会议中心 & 「JOISC 2021 Day4」活动参观 2)。
-
MST 有许多美妙的性质,这时候就可以分类讨论(「ARC093C」Bichrome Spanning Tree)。
-
有向图和无向图的最短路图都是 DAG,建出最短路 DAG 后一般就是直接 DP(「JOI 2018 Final」月票购买)。
-
按点分类 \(\rightarrow\) 按边分类(「CF1444C」Team-Building)。
-
矩阵乘法变式要满足结合律(「GZOI2017」河神)。
-
矩乘 = 暴力推式子 + 套模板(「GXOI/GZOI2019」逼死强迫症)。
-
棋盘计数问题考虑容斥(「CF1342E」Placing Rooks)。
-
DP 转移顺序有时候有妙用(「CF1497D」Genius)。
-
递增序列 \(\rightarrow\) 差分(「ABC221H」Count Multiset)。
-
曼哈顿距离不好做时可以考虑转切比雪夫距离;bitset 优化 01 背包(「ABC221G」Jumping sequence)。
-
要求构造的序列长度是 \(\log\) 级别的可以考虑二进制分组(「ARC103B」Robot Arms)。
-
树上到所有点距离和最大的一定是叶子(「ARC103D」Distance Sums)。
-
一些树形 DP 可以大胆换根(「ABC223G」Vertex Deletion)。
-
Dilworth 定理在构造时也可以用上(「ARC125C」LIS to Original Sequence)。
-
区间数字出现次数 \(\rightarrow\) 考虑上一个数字出现的位置,一般可以树状数组(「ARC125D」Unique Subsequence)。
-
trie 树合并 & 全局 \(+1\) 可以直接递归下去,复杂度是 \(\log\) 级别的(「联合省选 2020 A」树)。
-
有偏序关系的 DP 一般考虑数据结构优化(「NOI1998」免费的馅饼)。
-
\(a\mod b= a-\lfloor\frac{a}{b}\rfloor\times b\)(「CF1553F」Pairwise Modulo)。
-
多组询问最小次数可以考虑答案是否很小,说不定就是一个分类讨论题;与质因数相关的状态一般都很少(「CF1553G」Common Divisor Graph)。
-
跑最短路点数 / 边数很大时可以考虑让跑最短路的次数 \(\le\) 某个阈值(2021.9.25 T1)。
-
一些给点分组的题可以直接考虑并查集,因为这类题很有可能是诈骗题(2021.9.25 T2).
-
计数时直接计算不好优化可以考虑贡献法(2021.9.25 T4)。
-
与素数 / 数学有关的计数可以考虑结论(2021.9.27 T1)。
-
置换可以考虑倍增 / 快速幂(2021.9.27 T2)。
-
合并与拆分可以相互转化(2021.10.3 T1)。
-
字典树的实际含义:给定字符串集合中的任意一个字符串的任意一个前缀都会对应一个字典树结点。然后可以直接拆式子(2021.10.7 T3)。
-
mex 的性质:
- 把一个序列分成若干子序列使得子序列 mex 相同,那么这个值只能是全局 mex(2021.10.11 T2)。
-
树上与点权有关的问题可以考虑并查集重构树 / Kruskal 重构树(2021.10.11 T3)。
-
子串扩展一般都有单调性(P6652「SWTR-05」String)。
-
DAG 上求每个点到其他点的方案数可以在拓扑序上考虑(P6651 「SWTR-05」Chain)。
-
trie 树上交换两个节点可以打标记(「AGC044C」Strange Dance)。
-
设 \(inv_i\) 为以 \(i\) 开头的逆序对个数,则 \(inv_i\) 与排列 \(p\) 一一对应(2021.10.18 T2)。
-
有些最大化最小值可能并不需要二分,而是直接计算(2021.11.1 T3)。
-
网格上也可以考虑单调栈(2021.11.3 T3)。
-
对于代价计算关于 \(|S|\) 的,可以合并点数相同的状态,用空间换时间(2021.11.4 T2)。
-
\(n\le 50\) 可以考虑划分数(2021.11.8 T3)。
-
边数是 \(n^2\) 级别的最短路考虑使用朴素 \(\mathcal{O}(n^2)\) Dijkstra;最短路并不是一成不变的要令
dis[s] = 0;一些难以表示的转移可以建虚边(「CF1528D」It's a bird! No, it's a plane! No, it's AaParsa!)。 -
一棵树上的欧拉序 / dfn & low 要么包含,要么不交;set 不能对 begin 指针进行
--操作;一些可以写可回退化的东西就不要传参 / 直接返回了,e.g. 栈 / set(CF1528C Trees of Tranquillity)。 -
一种删掉一个数、它后面的数往前移一位的题可以考虑把数字换成 \(i-a_i\),就把操作变成了删掉一个 \(0\)、后缀 \(-1\)(「CF1404C」Fixed Point Removal)。
-
组合数前缀和可以用莫队,转移:参考;一些不好想的区间问题都可以想想莫队(2021.11.10 T1)。
-
单峰函数 \(f(x)\) 极值点 \(f'(x)=0\)(2021.11.10 T3)。
-
要让树上 \(k\) 条路径并权值和最大,可以找直径后长链剖分做(「CF526G」Spiders Evil Plan)。
-
直接贪心有问题时多考虑反悔,可以对拍找小数据(2021.11.11 T1)。
-
有关位运算的 DP:直接做不好优化时考虑按位做(「ARC116D」I Wanna Win The Game)。
-
找出 \(n\) 个数的最大值和最小值最少比较次数:\(3\lfloor\frac{n}{2}\rfloor-2\)(「JOISC 2014 Day1」拉面比较)。
-
碰到区间权值问题,可以考虑前缀和,转化为点权,然后运用数据结构即可(「NOI2010」超级钢琴)。
-
平面直角坐标系中从 \((0,0)\) 到 \((n,m)\) 不经过两条线的方案数可以用翻折容斥 + 经典卡特兰容斥(2021.11.13 T1 & 2021.11.15 T2 & 「JLOI2015」骗我呢)。
-
数据随机的题目可以多造几组随机数据找规律(2021.11.15 T1)。
-
\(n\) 个元素相互异或能构成的数字个数为 \(2\) 的(线性基元素个数)次方(XJOI NOIp #1 T2)。
-
图上最少经过多少条边 \(\rightarrow\) DP(XJOI NOIp #1 T3 & 「NOI2020」美食家 40pts 暴力)。
-
随机一个长度为 \(n\) 的排列的逆序对数的期望为 \(\frac{n(n-1)}{4}\);所有排列的逆序对数的和为 \(\frac{n!n(n-1)}{4}\)(XJOI NOIp #2 T2)。
-
树上路径问题的三角形不等式:\(dis_{u,v}\le dis_{u,w}+dis_{w,v}\),当且仅当 \(w\) 在 \(u\) 到 \(v\) 的路径上取等(XJOI NOIp #2 T4)。
-
\(u\oplus v\le\min(u,v)\rightarrow u\) 和 \(v\) 二进制最高位相同(「CF1605D」Treelabeling)。
-
图上构造问题一般都是先找一棵生成树出来;与点度数奇偶性有关的可以考虑 选择一条边会使这条边连接的两个点奇偶性状态改变(「CF840B」Leha and another game about graph)。
-
\(\binom{x+y}{x}\) 可以看成平面直角坐标系中 \((0,0)\) 到 \((x,y)\) 的路径数量(「AGC001E」BBQ Hard)。
-
推式子题可以正着不好推可以考虑反着推,即假设已知 \(a_n\) 推 \(a_1\),然后求出递推式(2021.11.17 T1)。
-
求第 \(k\) 大 / 小不只是数据结构,有时候也可以 DP,状态大概就是设 \(\ge x\) 的有多少个,查询的时候枚举 / 二分(2021.11.17 T2)。
-
与分割子树有关的贡献计算可以猜想是不是树的重心(2021.11.17 T3)。
-
不能选择连续的两个数使得选的数的权值和最大 \(\rightarrow\) 链表 + 反悔贪心(优先队列)(XJOI NOIp #3 T1)。
-
\(k\) 维空间从 \((0,0,\dots,0)\) 走到 \((x_1,\dots,x_k)\) 的方案数为 \(\prod\limits_{i=1}^k\binom{\sum\limits_{j=1}^k x_j}{x_i}\);\(\binom{a}{b}\equiv [(a\& b)=b]\pmod 2\);方案数为奇数当且仅当 \(\forall i\not =j,x_i\&x_j=0\);要求 \(k\) 个物品中每个物品 \(i\) 满足 \(val_i\in[L_i,R_i]\),当 \(k\) 较小的时候可以考虑状压(只强制集合 \(s\) 中的数上界为 \(L_i-1\),其余的数上界为 \(R_i\));题目给出一些限制时,考虑限制的本质是什么(XJOI NOIp #3 T2)。
-
“不经过 \(n\) 个点”之类的问题当 \(n\) 很小时可以考虑容斥;容斥 DP 的时候可以把容斥系数放进状态中转移;从 \((a,b)\rightarrow(c,d)\) 恰好走 \(p\) 步的方案数可以考虑双射,映射到两条路径 \(P_1\)、\(P_2\),对于每一步,在 \(P_1\) 增 \(x\) 还是增 \(y\) 帮助确定 \(P\) 操作符号,在 \(P_2\) 中增 \(x\) 还是增 \(y\) 帮助确定 \(P\) 操作 \(x\) 还是 \(y\),那么总方案数就是两条路径方案数的乘积,即设 \(u=|a-c|,v=|b-d|\),则方案数为 \(\binom{p}{\frac{p+u+v}{2}}\binom{p}{\frac{p-u+v}{2}}\)(XJOI NOIp #3 T4)。
-
单位圆中任取 \(n\) 个点,它们可以被同一个半圆包含的概率为 \(\frac{n}{2^{n-1}}\)(XJOI NOIp #4 T1)。
-
给一个连通图,问删去一些边是否使图不连通,考虑随机选一棵 DFS 树,对于非树边 rand 一个权值,树边权值是覆盖了它的非树边的权值的异或和,用线性基判断选的边集是否线性无关(即存在一个子集异或和为 \(0\))即可(DZY Loves Chinese II & XJOI NOIp #4 T3)。
-
形如 \(x\leftarrow x+y\) 之类的构造可以考虑斐波那契数(「ARC122C」Calculator)。
-
变换类问题首先要考虑这种变换能够生成的数列的集合是什么样的;形如 \(a_i\leftarrow a_{i-1}+a_{i+1}-a_i\) 之类的变换本质上就是交换差分数组的相邻两项(「NOIp2021」方差)。
-
一堆数字 \(\{a_i\}\) +1/-1 后要求连续的一段最长 \(\to\) \(a_i\leftarrow a_i-i\),然后二分长度,枚举左端点,最少操作次数可以直接取那一段的中位数(小学奥数知识/cy),最后判断操作次数即可(「ABC229G」Longest Y)。
-
区间覆盖、区间修改一般都可以考虑线段树,或者考虑势能线段树分析(「P4891」序列)。
-
利用线段树的分治结构可以直接用左右端点作为状态推式子(「P7143」[THUPC2021 初赛] 线段树)。
-
线段树区间定位懒标记问题考虑五种情况:https://www.luogu.com.cn/blog/Thinking/solution-p6630 & https://www.luogu.com.cn/blog/ix-35/noi-yi-lun-fu-xi-iii-shuo-ju-jie-gou(「ZJOI2020」传统艺能)。
-
带懒标记的主席树在新建节点时 不要传递懒标记;pushdown 每次都要新建节点,空间要开到 \(70\) 倍左右(「BZOJ4504」K个串)。
-
\(\varphi(ab)=\dfrac{\varphi(a)\varphi(b)\gcd(a,b)}{\varphi(\gcd(a,b))}\);看到 \([\gcd(i,j)=1]\) 就要想到莫反式子:\([\gcd(i,j)=1]\Leftrightarrow\sum\limits_{d|i,d|j}\mu(d)\)(「CF809E」Surprise me!)。
-
树上路径问题可以考虑转换成欧拉序;控制若干个点使贡献最大用线段树可以强制保证前/后若干个点贡献最大,pushup 更新一下即可(「CEOI2019」Dynamic Diameter)。
-
线段树上二分一定要注意边界问题!!!(「联合省选 2020 A | B」冰火战士)
-
可持久化数据结构一定要记得最开始要建一棵全 0 的数据结构。
-
线段树分治有时候写的方式会和整体二分的形式相似,写的时候要分清楚哪样写;看到区间问题和 \(\text{xor}\) 就要想到可持久化 trie(「FJOI2015」火星商店问题)。
-
树上距离在括号序列上的体现就是把
(看成 \(+1\),)看成 \(-1\),然后把树的欧拉序取出来,一个区间的值是找到一个分割点使得右半部分的和减去左半部分的和最大,树的直径就是所有区间的值的最大值;树上路径问题可以通过 dfs 序、欧拉序等转化到序列上来(「CF1149C」Tree Generator™)。 -
区间数颜色:在线段树上记录每个点之前和它颜色相同的最近的点(即前驱,可以用 set / multiset 很好地维护),判断区间 \([l,r]\) 是否包含所有颜色可以通过判断 \([r+1\),末尾\(]\) 的最小值是否 \(\ge l\);线段树分治如果能转化成扫描线就尽量写扫描线,毕竟常数和代码量都小一些(「APIO2018」New Home 新家)。
-
一些奇怪的限制(如:至少 \(20\%\) 有解、数据随机等)可以想象随机化,找出一个特解后推出其它解(「CF1361E」James and the Chase)。
-
线段树分治的时候如果一个操作有条件满足才能执行并且对以后都有影响,那么就需要每次查询时间 \(t\) 的操作之后修改区间 \([t+1\),下一次操作这个点的时间\(]\),这样才能够保证复杂度;判断二分图用扩展域并查集,每次
unionn(u,v+n),unionn(v,u+n),查询的时候若 \(u\) 和 \(v\) 在同一个连通块就说明不是二分图(「CF576E」Painting Edges)。 -
中位数可以考虑二分之后把 \(\ge\) 的权值设成 \(1\),\(<\) 的权值设成 \(0/-1\);01 序列区间排序 \(\to\) 从小到大:0 放左边,1 放右边;从大到小:1 放左边,0 放右边;询问若干操作后某 一个 位置上的值用二分(「HEOI2016/TJOI2016」排序)。
-
第 \(k\) 大:堆 / DP;区间 \(\text{xor}\) 和最大 \(\to\) 可持久化 trie(「十二省联考 2019」异或粽子)。
-
存在一个边集满足每个点度数都为奇数 \(\to\) 图中没有大小为奇数的连通块;满足某种条件要求最小化选的边的最大边权 \(\to\) Kruskal 重构树(「CF603E」Pastoral Oddities)。
-
区间历史最值:多记录一个标记 \(pre_p\) 表示上次修改到现在 \(add\) 标记的最大值,每次 pushdown 更新即可;区间赋值记得每次多开一个标记(「P4314」CPU 监控)。
-
形如区间 \(a_i\leftarrow \max(a_i-x,0)\) 之类的操作可以考虑定义一个标记 \((a,b)\) 表示这个节点中的数加上 \(a\) 后和 \(b\) 取 \(\max\)。对于两个标记 \((a,b)\) 和 \((c,d)\) 就合并成 \((a+c,\max(b+c,d))\);注意吉老师线段树每次 pushdown 后 所有标记 都要清空(「UOJ164」【清华集训2015】V)。
-
主席树要弄清楚要将什么离散化、不能将什么离散化;可以考虑离线的区间操作就离线下来通过差分转成单点操作(「CQOI2015」任务查询系统)。
-
主席树区间修改需要使用标记永久化(其实也可以下传,只是空间还要额外开 \(4\) 倍),这时需要特别注意修改和查询的细节,具体可参考如下代码(「SP11470」TTM - To the moon):
namespace CT { struct Node {int ls, rs, add; LL sum;} tr[N * 70]; #define ls(p) (tr[p].ls) #define rs(p) (tr[p].rs) void build(int &p, int l, int r) { p = ++tot; if (l == r) return (void)(tr[p].sum = a[l]); int mid = (l + r) >> 1; build(ls(p), l, mid); build(rs(p), mid + 1, r); tr[p].sum = tr[ls(p)].sum + tr[rs(p)].sum; } void modify(int &p, int q, int ql, int qr, int val, int l, int r) { p = ++tot; tr[p] = tr[q]; if (ql <= l && r <= qr) {tr[p].add += val; return;} int mid = (l + r) >> 1; if (ql <= mid) modify(ls(p), ls(q), ql, qr, val, l, mid); if (qr > mid) modify(rs(p), rs(q), ql, qr, val, mid + 1, r); tr[p].sum = tr[ls(p)].sum + tr[rs(p)].sum + 1ll * (mid - l + 1) * tr[ls(p)].add + 1ll * (r - mid) * tr[rs(p)].add; //!!! } LL query(int p, int ql, int qr, int l, int r) { if (ql == l && qr == r) return tr[p].sum + 1ll * tr[p].add * (r - l + 1); //!!! int mid = (l + r) >> 1; LL val = 1ll * tr[p].add * (qr - ql + 1); if (qr <= mid) return val + query(ls(p), ql, qr, l, mid); if (ql > mid) return val + query(rs(p), ql, qr, mid + 1, r); return val + query(ls(p), ql, mid, l, mid) + query(rs(p), mid + 1, qr, mid + 1, r); //!!! } } //namespace CT using namespace CT; -
给出一个 01 序列和一个集合 \(B\),每次选择一个长度为 \(B\) 中某个元素的区间 01 翻转,那么所有操作都可以转化成对长度为 \(B\) 中所有元素 \(\gcd\) 的区间操作(「CF1630D」Flipping Range)。
-
给出若干区间 \([l_i,r_i]\),每次可以选择一个两个断电都还存在的区间和另一个在 \([l_i,r_i]\) 范围内的端点 \(x\),删去点 \(x\),要求删去的点最多 \(\Rightarrow\) 正难则反,将问题变成最少保留多少个点。考虑 DP,设 \(f_i\) 表示 \([1,i]\) 最少保留多少个点,则可以进行如下转移(\(r_{a_i}\) 为 \(i\) 对应的右端点):
int mx = 0; for (int i = 1; i <= n; i+=1) { chkmin(f[i], f[i - 1] + 1); chkmax(mx, r[a[i]]); chkmin(f[mx], f[i] + 1); }含义:每次可以保留这个点;可以把 \([i+1,r_{a_i}]\) 之间的点全部删掉(「CF1630C」Paint the Middle)。
-
找到一个区间 \([x,y]\) 使得 \(y-x\) 最小 \(\Rightarrow\) 双指针。如果不能快速判定就一定是有什么性质没被发现(「CF1630B」Range and Partition)。
-
树上区间转移的 DP 考虑线段树合并维护(「JOISC 2021 Day4」最差记者 4)。
-
整体 DP 要分析清楚前缀后缀和转移到哪里,然后下传标记也就不会很难了(「PKUWC2018」Minimax)。
-
通信题一种压缩信息的常见技巧:向等比数列拟合(「JOISC2017」K - 都市 (City))。
-
对于每个 \(r\),满足条件 \(\gcd(a_l,a_{l+1},\dots,a_r)=r-l+1\) 的 \(l\) 最多只有一个(「CF1632D」New Year Concert)。
-
求每个子树内的直径时,对于每个点不要忘记与它的子节点的子树直径取 max;加一条边后删一条边 \(\to\) 删一条边后加一条边(「CF1632E」Distance Tree)。
-
递推可以考虑从变化量的角度去推式子;对于经过一条边后当前权值 \(\times2\),可以考虑分层图(「JOIG 2022 F」タクシー 2 (Taxis 2))。
-
如果每个点有一个类别,询问也与类别有关,那么可以考虑将点分类考虑(「JOI 2021/2022 二次予選 E」交易計画 (Trade Plan))。
-
包含若干点的虚树边集大小:\(\sum dep_{a_i}-\sum dep_{\text{LCA}(a_i,a_{(i+1)\% n})}\),\(a_i\) 按照 dfs 序排序;用线段树维护连续一段 dfs 序的虚树边集大小;树上路径 \(\to\) 树上差分;碰到树上贡献计算类的问题首先要想到线段树合并(「ZJOI2019」语言)。
-
对于区间询问可以莫队但强制在线的题,可以考虑分块求出每一块到结尾的答案,询问时整块直接处理,散块暴力即可(「P4135」作诗)。
-
如果有一堆区间,可以对区间分块,差分后算出每一块内的区间的和,套上修改就加一个树状数组;\(10^{19}\) 记得开
unsigned long long(「CodeChef FNCS」Chef and Churu)。 -
对于计算“对子”贡献的问题,可以每次考虑新加入元素和旧元素之间的贡献;看到区间异或和,马上想到异或前缀和 & 差分;一般莫队块大小为 \(\frac{n}{\sqrt{m}}\)(「CQOI2018」异或序列)。
-
对于给出两个区间 \([l_1,r_1]\) 和 \([l_2,r_2]\),要求的量与两个区间同时出现的数的个数有关,那么可以考虑拆成 \([1,l_1-1]\)、\([1,r_1]\)、\([1,l_2-1]\)、\([1,r_2]\) 四个区间,用差分 & 拆式子解决问题(「SNOI2017」一个简单的询问)。
-
带修莫队其实就是普通莫队加上时间轴一维,排序的时候按照 \(l\)、\(r\)、时间的顺序排序,调整时间时如果修改的点在当前维护的区间里就进行修改;块大小为 \((nq)^{\frac{1}{3}}\)(「国家集训队」数颜色 / 维护队列)。
-
回滚莫队:按照左端点所在块、右端点的顺序排序,每次对于同一块处理的时候直接移右端点,左端点从当前块最右边的点开始动,操作完后还原所有记录,左端点移到当前块最右边的点。实现时务必注意:先判断是否移动了块,再处理同一块内询问;处理同一块内询问也务必要回滚操作。参考:https://www.luogu.com.cn/blog/command-block/mu-dui-yang-xie & https://www.cnblogs.com/Parsnip/p/10969989.html(「P5906」【模板】回滚莫队&不删除莫队)。
-
树上带修莫队在判断是否需要修改时直接看 \(rev_x\) 是否为 \(1\),即 \(x\) 是否在当前维护的区间中,不需要看是否在当前维护的区间中(「WC2013」糖果公园)。
-
贡献与区间内信息有关考虑分治(「COCI2014-2015#2」Norma)。
-
构造题常见做法:递归到子问题;找到一个特解再扩展到通解;加强限制。
-
形如对于每一个 \(i\),给出最大的下标 \(j\) 满足某个限制,要求构造之类的问题,可以考虑强制 \(j\) 满足限制,\(j+1\) 以后的都不满足限制(「USACO22JAN」Tests for Haybales G)。
-
一些题目操作如果有限制条件有时可以忽略,这就要求要看清题目(「USACO22JAN」Farm Updates G)。
-
从交互次数寻找到复杂度有关信息,从而确定方向,如按位做、枚举等(「CF835E」The penguin's game)。
-
现在市面上的计数题基本上都是 DP(「USACO22JAN」Drought G)。
-
以 \(u\) 为根的子树内的重心一定是在 \(u\) 开头的重链上,由此性质可以换根 + 倍增找出所有子树内的重心(「CSP-S2019」树的重心)。
-
与置换有关的构造从每个环考虑(「CF1063E」Lasers and Mirrors)。
-
构造考虑计算相邻取值之间的差值,然后可以优先队列 / 二分(「CF1344D」Résumé Review)。
-
设 \(cnt_i\) 表示 \(i\) 在序列中的出现次数,则 \(cnt_i\) 的种类数 \(\le \sqrt{n}\)(「CF1637E」Best Pair)。
-
在某些 连通性问题 / 完全图最小(最大)生成树 中可以考虑 Borüvka 算法:每次每个联通块找到最小的连向其他联通块的边,然后合并。这样每次会使点集缩小到原来的 \(\frac{1}{2}\),会重复 \(O(\log n)\) 次,复杂度 \(O(n \log n)\)(「CF1550F」Jumping Around)。
-
考虑遍历 trie 树的过程,如果可以简化过程,那么可以改变 trie 树的构造方式,如:倒着建 / 从低位往高位建 / 合并左儿子和右儿子(「UOJ176」新年的繁荣)。
-
Prüfer 序列的推论:有 \(k\) 个连通块,点数分别为 \(s_1 , \dots , s_m\),将它们连成树的方案数为 \(n^{k−2}\prod s_i\)(「CF156D」Clues)。
-
扩展 Cayley 定理:有 \(n\) 个有标号点连成 \(s\) 个连通块(且 \(1,\dots, s\) 属于不同连通块),方案数为 \(sn^{n-s-1}\)。如果是有根树,则为 \({n\choose s} sn^{n−s−1}\)。可以枚举点 \(1\) 的度数用归纳法证明。
-
点分治也能处理连通块问题:强制分治重心 \(x\) 一定在连通块里,然后对当前子树进行扫描,如果有要选的点不在当前子树内说明当前决策不优;处理点的合并问题可以考虑用队列,每次加入当前点 \(u\) 的父亲(「JOISC2020」首都)。
-
树哈希可以考虑转成括号序列,然后变成字符串哈希,具体可见 https://www.cnblogs.com/werner-yin/p/15893929.html;双哈希可以用重载 pair 的
*和+运算符减少代码量(「CF718D」Andrew and Chemistry)。 -
DP 转移注意顺序;输出的答案为浮点数的时候可以考虑少算一些精度能够忽略不计的东西,这一点在概率题中很常见(「CF643E」Bear and Destroying Subtrees)。
-
LCA 的本质刻画:将点 \(u\) 到根的所有节点标记 \(+1\),查询 \(v\) 到根的有标记的节点数量。
-
主席树卡空间技巧:定时重构。
-
直径的交只能是一个点 / 一条边,可以维护两个集合使得一个集合中的每个点到另一个集合中的每个点的路径都是直径(「CF842E」Nikita and game)。
-
欧拉回路注意:当前弧优化(用
&实现);在回溯的时候加入答案;倒序输出。 -
儿子个数的奇偶性 \(\to\) 度数的奇偶性 \(\to\) 构造一个图跑欧拉回路(「AGC018F」Two Trees)。
-
计算子树内贡献的时候有一个 trick:\(\sum\limits_{v\in sub_u}deg_v=2sz_u-1\),化简成 \(\sum\limits_{v\in sub_u}(2-deg_v)=1\),这样可以令每个节点有一个权值 \(2-deg_u\),将问题转化(「USACO18JAN」Cow at Large P)。
-
形如“加入一个点后任何其他点到 \(s\) 的最短路 可以不经过 新点”的限制实际上是限制了新点的加入不会改变原图中 \(s\) 的最短路,即 \(dis(s,i)\)、\(dis(s,new)\) 和 \(dis(new, i)\) 满足三角形不等式;看到最小化 \(\sum\max\{|f_i-a|,|g_i-b|\}\),其中 \(a\)、\(b\) 为定值,马上想到切比雪夫距离转成曼哈顿距离,这样的好处是两维独立,分别取中位数取到最小值(「Gym100624F」「CERC2012」Farm and Factory)。
-
同余最短路的核心:选一个数为基 \(s\),那么若 \(a\) 满足条件,则 \(a+ks\) 也肯定满足条件;以 \(x\) 为首项,\(a\) 为公差的等差数列有多少个数在 \([l,r]\) 中出现 \(\to\) \([1,r]\) 的个数 \(-[1,l-1]\) 的个数(「P2371」[国家集训队]墨墨的等式)。
-
边双连通分量也可以用栈来求(「CEOI2017」One-Way Streets)。
-
网格图套路除了黑白染色之外,还可以将行和列分开考虑(「HEOI2016/TJOI2016」游戏)。
-
黑白染色:令黑点权值为 \(1\),白点权值为 \(-1\),则一个点被覆盖成黑点和白点的次数的差的绝对值 \(\le1\) 等价于这个点的权值 \(\in[-1,1]\);欧拉回路题对于奇度点的处理:相邻奇度点连边;建一个虚点向所有奇度点连边(「CF429E」Points and Segments)。
-
网格类的题常见套路:行、列转点,点转边。
-
求将 \(k\) 个点连通的一棵 边权 / 点权 最大 / 最小 的一课生成树 \(\to\) 斯坦纳树。
-
枚举两层出边可以想到 \(\mathcal{O}(m\sqrt m)\) 的三元环计数;vector 中删除一个元素:将当前元素与 vector 最末元素交换,然后
pop_back()(「POI2013」CEN-Price List)。 -
仙人掌 / 与两点之间所有简单路径有关的信息 \(\to\) 圆方树。
-
2-SAT 也可以有很多变量,可以多设一些(「UOJ210」【UER #6】寻找罪犯)。
-
看到每个点有两个属性,每次操作修改属性要敏感地想到按照属性的 差值 / 和 的大小排序;维护
0/1的值用 bitset(2022.2.17 T2)。 -
维护平面矩形相关信息 \(\to\) k-D Tree。
-
优化建图不一定要显式连边,要松弛的时候访问节点就行(「NOI2019」弹跳)。
-
k-D Tree 也可以像线段树那样建树、维护信息(「CF44G」Shooting Gallery)。
-
多次询问且答案具有单调性 \(\to\) 整体二分(「CTSC2018」混合果汁)。
-
到一些点距离之和最小的点集一定是在一条链上(「JOISC 2021 Day3」聚会 2)。
-
看到 \(n^k\) 之类的要想到第二类斯特林数拆式子(「洛谷 P4827」[国家集训队] Crash 的文明世界)。
-
如果暴力复杂度与度数有关,那么可以想想能不能重儿子直接做,轻儿子打标记处理,因为一个点到根的路径上轻边数量是 \(\mathcal{O}(\log n)\) 的(「CF1254D」Tree Queries)。
-
\(\sum dep\) 可以把贡献转移到子树,因为 \(\sum dep = \sum size\)。
-
长度在 \([l,r]\) 之间的路径统计 \(\to\) 点分治(「BJOI2017」树的难题)。
-
将序列分成若干段,每段贡献可能可以独立算,这样就互不影响;如果有影响,就可以想想图论模型 / DP / 网络流(「JOISC 2015 Day2」Keys)。
-
到所有节点距离和最小的节点是树的重心;与重心有关的题可以先想想有两个重心的时候怎么算,再扩展到一个重心的情况(「雅礼集训 2017 Day7」跳蚤王国的宰相)。
-
最短路不能经过同一个点 / 同一条边,因此有的题看似复杂,实际上建模很简单(「JOISC 2016 Day 4」危险的滑冰)。
-
斜率优化一定要注意 \(X(j_1)=X(j_2)\) 的情况,应该返回
Y(j2) >= Y(j1) ? inf : -inf。 -
单次询问可以点分治,多次询问就可以用动态点分治 / 点分树。
-
支持删除 / 查询最值 \(\to\) multiset。
-
一些计数问题如果物品有个数限制,那么可以考虑按照根号分类(「LOJ6089」小 Y 的背包计数问题)。
-
在序列问题上用并查集 + 启发式合并的时候应该这样写:
inline void Union(int x, int y) { int fx = getf(x), fy = getf(y); if (fx != fy) { fa[fx] = fy; if (s[fx].size() > s[fy].size()) swap(s[fx], s[fy]); for (auto p : s[fx]) s[fy].insert(p); set <int> ().swap(s[fx]); } } ...... for (int i = getf(r); i >= l; ) Union(i, i - 1), i = getf(i); -
构造题 一定 是想一种基本操作,然后根据基本操作完成构造,上界 可能 会有一定提示(「CF1641B」Repetitions Decoding)。
-
两个序列 \(\{a\}\) 和 \(\{b\}\) 没有相同元素的判断方法:记一个计数器 \(cnt\),对于每一个 \(b\) 的子集,如果它的元素个数是奇数,就将 \(cnt\) 加上它在 \(a\) 中的出现次数,否则就减去它在 \(a\) 中的出现次数。最后如果 \(cnt=1\) 说明 \(a\) 和 \(b\) 至少有一个元素相同,否则它们就没有相同元素(「CF1641D」Two Arrays)。
-
排列计数一般考虑 DP,DP 时记录连通块数量维,再记一个边界情况,转移的时候系数只需要考虑相对位置关系(「ZJOI2012」波浪)。
-
从转移中发现状态之间的关系,然后优化状态表示(「JOISC 2015 Day 3」Card Game Is Great Fun)。
-
两个字符串比较大小:先求出 LCP,然后根据 长度 / LCP 后一位比较;与字符串字典序有关的 DP 一般考虑从后缀角度设状态,因为一个字符串不断往后面加字符字典序不会下降(「CF1310C」Au Pont Rouge)。
-
组合数对小模数取模用 Lucas 定理(「BZOJ4403」序列统计)。
-
看见给一个排列,然后权值根据相邻大小关系的题目(一般会带绝对值)要迅速反应到从小到大加权值,维护连续段(一段紧挨着的数,中间没有空隙,不能再放数)(「CF704B」Ant Man)。
-
构造一棵树满足度数条件有两种做法(「ABC239F」Construct Highway):
- 将并查集集合分成 vector 大小 \(=1\) 和 \(\ge2\) 的,每次将一个 \(\ge2\) 的集合与 \(=1\) 的集合匹配,并且最后留一个元素放到 \(=1\) 的集合里面。最后会剩下两点一边。
- 将集合按照度数从大到小加入到一个优先队列里,每次取出度数最大的两个集合合并。
-
看到偏序关系,马上想到排序;偏序问题如果值域很小可以考虑把值域放进状态 DP(「ABC238F」Two Exams)。
-
与每一位数值有关的限制 \(\to\) 高维前缀和(「ARC136D」Without Carry)。
-
环上选择一段区间 \(+1\),问将全 \(0\) 环变成所要求的环所需的最小操作次数:\(\max(\max(a_i),\sum|a_i-a_{i-1}|+|a_n-a_1|)\)(「ARC136C」Circular Addition)。
-
看到区间被某个数整除,就要快速想到转化成前缀和 / 后缀和的形式(「ARC129C」Multiple of 7)。
-
对于离上一次操作要过 \(t\) 时间再能操作的限制,考虑把操作时间积累下来,要操作的时候就倒回上次操作后 \(t\) 时间再进行操作(「CF936D」World of Tank)。
-
\(E[(x+y)^2]=E(x^2)+yE(x)+y^2\)(2022.3.1 T2)。
-
\(\sum\limits_i a_i=\sum\limits_i\sum\limits_j[a_i\ge j]\)(2022.3.1 T3)。
-
对于与所有儿子都有关的 DP,要先把子树 DP 完再进行当前节点的 DP(「CF1276D」Tree Elimination)。
-
看到与区间最大值有关的计数,马上想到最值分治;多次查询 区间最值 / 区间最值所在的位置 用 ST 表;主席树查询 \(\le\) 某个数的个数的细节:应该先递归左区间,再在 \(x>mid\) 的情况下递归右区间(「洛谷 P4755」Beautiful Pair)。
-
与区间 / 时间有关的操作都可以用线段树分治;用一堆数能不能拼成一个数 \(\to\) bitset 优化背包(「CF981E」Addition on Segments)。
-
对于与区间 0/1 状态有关的问题,要想到用 set 维护连续段;询问与区间有关的问题可以转化到坐标系上:横坐标是左端点,纵坐标是右端点;求某段区间保持某个状态的时间:设当前时间为 \(i\),则在不满足变成满足时 \(-i\),满足变成不满足时 \(+i\);矩形加、单点查在差分后变成单点加、矩形查,就可以用树状数组套线段树解决(「APIO2019」路灯)。
-
有的时候如果树上单独有一个节点需要特殊处理就可以直接以这个节点为根(「CF1637F」Towers)。
-
形如“经过若干次操作(操作可以修改),问能到达多少网格上的点”之类的题目可以考虑循环节 / 将操作分成前缀后缀考虑(「CF1644E」Expand the Path)。
-
对于可以写出两种复杂度不同的暴力的题目考虑根号分治;一个 \(m\) 条边的图度数 \(\ge B\) 的点的数量不超过 \(\frac{2m}{B}\)(「ABC219G」Propagation)。
-
对于每一个子区间都满足 \(a_l+a_{l+1}+\dots+a_r=\frac{1}{2}\times(r-l+1)\times(a_l+a_r)\) 等价于这个序列是一个等差数列(「CF1616C」Representative Edges)。
-
形如 \(a_l+a_{l+1}+\dots+a_r\ge x\times(r-l+1)\) 之类的条件,可以考虑将每一个 \(a_i\leftarrow a_i-x\)(「CF1616D」Keep the Average High)。
-
字符串问题可以考虑 fix 一段前缀;对于移动字符的问题,可以考虑记一个树状数组 \(\{tr_i\}\) 表示原本 \(s_i\) 上的字符现在的位置与当前 \(len\) 的差(「CF1616E」Lexicographically Small Enough)。
-
DAG 给所有点分配编号使得字典序最小 \(\to\) 建反图后把尽量大的数分配给编号大的点(「CF825E」Minimal Labels)。
-
对于题目中给的数有一定条件 / 限制的时候一定转化成好解决的问题;选一个子集和为 \(0\) 并求一种方案 \(\to\) 转成一个基环树后找环(「CF1270G」Subset with Zero Sum)。
-
有时候形如“最多进行几次操作”之类的问题可以分别考虑答案的上界和下界(「CF1348E」Phoenix and Berries)。
-
图上恰好走 \(L\) 步 \(\to\) 矩阵乘法(「ABC236G」Good Vertices)。
-
构造题不好想的话考虑进行一次 / 两次操作后对原序列的影响,说不定会发现操作的本质(「CF1615C」Menorah)。
-
\(\text{popcount}(x\oplus y)\mod 2=(\text{popcount}(x)\mod2)\oplus(\text{popcount}(y)\mod 2)\);给出一堆 \(0/1\) 变量和一堆与位运算有关的条件考虑扩展域并查集 / 2-SAT(「CF1615D」X(or)-mas Tree)。
-
选一堆叶子,要求它们到根的路径的并的长度最大 \(\to\) 长链剖分后选最长的若干个链;式子的变量太多考虑利用变量之间的关系化简式子(「CF1615E」Purple Crayon)。
-
把两个相邻的 \(0\) 变成 \(1\) 或者把两个相邻的 \(1\) 变成 \(0\to\) 将所有奇数位上的 \(0\to1\),\(1\to0\),这样每次操作就是交换相邻的两个 \(01/10\);给出两个 \(01\) 串 \(s\) 和 \(t\),每次交换两个相邻字符,问最少多少次操作后 \(s\) 能变成 \(t\to\) 答案就是 \(\sum\limits_i\) 两个串中第 \(i\) 个 \(1\) 的位置差。也可以考虑转化一下:设 \(x_i=\sum\limits_{j=1}^i[s_j=1]\),\(y_i=\sum\limits_{j=1}^i[t_j=1]\),那么最小次数就是 \(\sum\limits_{i=1}^n|x_i-y_i|\)。意思就是说每一个 \(s\) 中的第 \(i\) 个 \(1\) 对 \(t\) 中第 \(i\) 个 \(1\) 的贡献是二者的位置差(「CF1615F」LEGOndary Grandmaster)。
-
插入一次函数 / 线段,查询在某一点 / 区间上的最值 \(\to\) 李超线段树。
-
李超线段树合并是 \(\mathcal{O}(n\log n)\) 的。
-
区间内一次函数最值只会在两端取到;李超线段树也可以维护区间最值,加一个值记录即可;实现的时候结构体写一个构造函数可以避免一些边界问题;区间修改建议写代码时使要修改的区间完全被包含于当前区间(「SDOI2016」游戏)。
-
当发现有一种操作的范围与笛卡尔树类似的时候,想想问题有没有偏序关系满足,将笛卡尔树上的 DP 转成序列 DP(3.5 考试 T2)。
-
数数要么是 DP,要么是容斥算(「ABC242F」Black and White Rooks)。
-
完全图 MST \(\to\) Borüvka 算法(「USACO22FEB」Moo Network G)。
-
一些数据范围很小的题目也可以结合题目性质想想高维 DP(「ABC233G」Strongest Takahashi)。
-
看到曼哈顿距离,立马想到能不能转成切比雪夫距离;在线询问的二维数点 \(\to\) 二维树状数组(动态开点)/ 主席树(「ABC233H」Manhattan Christmas Tree)。
-
DP 转移与区间最大值 / 最小值有关可以考虑用单调栈优化转移(「ABC234G」Divide a Sequence)。
-
平面问题优先考虑 k-D Tree 暴力(「ABC234H」Enumerate Pairs)。
-
DP 转移与下取整有关时考虑把下取整值相同的放在一起转移(「USACO22FEB」Cow Camp G)。
-
求一个点到根的路径上的点的其它子树内的信息可以通过正反两遍 dfs 求出,即(3.7 考试 T3 白色夫人的根):
dfs(u) 查询 u 遍历 u 的子树 加入 size_u -
完全图最短路 \(\to\) 利用边权性质优化连边(「ABC232G」Modulo Shortest Path)。
-
类似连边的过程的问题 / 网格问题可以考虑转化成图论问题;发现问题有点像 \(n\) 元环可以考虑 \(n\) 染色(「AGC006F」Blackout)。
-
求与乘积有关的期望可以尝试将变量拆成若干随机变量的乘积,然后推式子(「ABC231G」Balls in Boxes)。
-
每次增加一个限制 \(\to\) 使用每次修改只会改 \(\mathcal{O}(\log)\) 个区间的线段树(「CF1286D」LCC)。
-
如果问题直接做并不好做,那么可以找出贡献的充要条件,然后状态互补(「洛谷 P1502」窗口的星星)。
-
DP 转移形如一次函数 \(\to\) 李超线段树(「CEOI2017」Building Bridges)。
-
与区间内数字出现次数有关的限制 \(\to\) 记录前驱;区间统计某个数的个数可以根据值域范围考虑特殊的解法(3.1 考试 T1 单次出现)。
-
考虑题目的限制要想想能不能把一些情况独立计算;一定要利用好题目的每一个条件(3.1 考试 T2 完美覆盖)。
-
团 \(\to\) 补图上两两都没有边。
-
\(x\) 子树内距离点 \(x\) 距离 \(\le k\) 要想到主席树。具体的,将点按照深度从小到大插入,主席树下标为 dfs 序(「CF893F」Subtree Minimum Query)。
-
计算总贡献 \(\to\) 考虑每个点对答案的贡献;虚树差分:将虚树上的每个点权值置为 \(1\),然后在 dfs 序相邻的两个点的 LCA 处权值 \(-1\),对于每一个点,它子树内所有点的权值和就是它的贡献。这样就把问题转化成了单点加和子树查(「BZOJ4771」七彩树)。
-
多次询问、每次询问的范围是一个区间 \(\to\) 主席树(「JSOI2018」列队)。
-
\(10^7\) 以上量级的递推如果复杂度够就可以矩乘(3.14 考试 T1 上进心)。
-
维护前驱后继、可删除、可撤销 \(\to\) 链表;插入和删除有一个更简洁 \(\to\) 回滚莫队(「WC2022」秃子酋长)。
-
互质 \(\to\) 质因子组成交集为空;在 __int128 范围内的答案都可以打表(3.15 考试 T1 排列)。
-
树上 DP 带修可以考虑 DDP;树剖 + 矩阵优化 DP \(\to\) DDP。
-
bitset 优化字符串匹配:开 \(|\sigma|\) 个 bitset \(t_i\) 存下每个字符在原串中的出现位置,修改也可以很好维护。匹配的时候存一个 bitset \(ans\) 表示模式串在原串中的所有出现位置,初始全为 \(1\)。对于模式串 \(y\) 的每一个字符 \(y_i\),将 \(t_{y_i}\) 左移 \(len-i\) 位再与上 \(ans\),即 \(ans\leftarrow ans\ \operatorname{bitand}\ (t_{y_i}<<(len-i))\)。
-
互不相同的长度之和为 \(M\) 的字符串的 \(\text{endpos}\) 集合大小之和不超过 \(n\sqrt m\)(「CF963D」Frequency of String)。
-
一个数 \(x\) 有原根当且仅当 \(x=1/2/4/p^k/2p^k\),其中 \(p\) 为奇质数。
-
一般地,对于(完全图)MST 问题,我们可以先选定一个 边集,做一次 MST(不连通不管),把剩余的边保留,最后再做一次 MST,这样一定能得到最优解(CODE FESTIVAL 2017 Final J - Tree MST)。
-
一般的,图上距离与树相关的问题都要进行树分治。
-
求出离每个点最近的关键点 \(\to\) 多源 Dijkstra。
-
如果算的概率很小可以考虑取 \(\log\) 计算(3.17 考试 T2 随机字符串生成器)。
-
扩展欧拉定理:
\[a^b\bmod p= \begin{cases} a^{b\ \bmod\ \varphi\left(p\right)} &\gcd\left(a,p\right)=1\\ a^{b} &\gcd\left(a,p\right)>1\ \land\ b<\varphi\left(p\right)\\ a^{b\ \bmod\ \varphi\left(p\right)+\varphi\left(p\right)} &\gcd\left(a,p\right)>1\ \land \ b\ge\varphi\left(p\right) \end{cases} \]由于当 \(\gcd\left(a,p\right)=1\) 的时候 \(a^{\varphi\left(p\right)}\equiv 1\pmod p\),所以上式可以等价于:
\[a^b\bmod p= \begin{cases} a^{b} &b<\varphi\left(p\right)\\ a^{b\ \bmod\ \varphi\left(p\right)+\varphi\left(p\right)} &b\ge\varphi\left(p\right) \end{cases} \] -
如果贡献是形如 \(a_1^{a_2^{a_3^{\dots}}}\) 的幂塔,那么根据扩展欧拉定理,在 \(\mathcal{O}(\log\ \rm{mod})\) 的时间内模数就会变成 \(1\),所以只要暴力处理到模数为 \(1\) 就行了。注意在使用扩展欧拉定理的时候要在快速幂里判断当前幂的值是否大于等于模数;卡常小技巧:把 mod 设置成一个常量,编译器就会把除法优化成乘法和右移(3.19 考试 T1 灰色王子左特 zote)。
-
对于要求分配一些物品,价值最大 / 最小,且价值和选择物品属性的最值有关时,可以考虑枚举属性的最值(3.19 考试 T2 小 ds,确信 tinyds)。
-
模拟退火就是每次在一个范围内随机一个取值,如果它比当前解更优就更新当前最优解,否则以 \(e^{\frac{\Delta}{T}}\) 的概率接受当前位置,代码里的体现就是
if (exp(-Dlt / T) * RAND_MAX > rand()) tx = nx, ty = ny;(接受解)。一些调参:随机种子:
srand(19491001); srand(rand()); srand(rand());或者srand(19260817); srand(rand()); srand(rand());;温度 \(T\) 初值 \(2000\),温度变化量 \(\Delta=0.9975\),eps 为 \(10^{-14}\),卡时if ((double)clock() / CLOCKS_PER_SEC > 0.993) {printf("%lld\n", ans); exit(0);}。 -
如果图的限制条件和边权有关,那么考虑将边权设进状态 DP(「CF1657E」Star MST)。
-
动态删字符匹配的问题考虑用栈维护还留着的字符,并且记下每个前缀匹配到的位置(「USACO15FEB」Censoring G)。
-
AC 自动机转移的量与 fail 有关的时候要在 BFS 时转移,而不是单独拿出来再转移,因为要先转移完 fail 在转移自己(AC 自动机上的 DP 问题)。
-
对于同时与两个字符串相关的问题,考虑 在拼接处计算贡献(「CF1202E」You Are Given Some Strings...)。
-
一张 DAG 包含至少一个以 \(A\) 为根的外向树等价于除了 \(A\) 以外的所有点入度至少为 \(1\)。内向树则等价于除了 \(B\) 以外的所有点出度至少为 \(1\);将点集 / 边集划分成两个集合 \(\to\) 网络流 / 拆点二分图(3.25 考试 T1 鬼灵贼 spectral)。
-
与图上距离相关的最优化问题可以考虑拿出一棵生成树然后跑树分治(3.25 考试 T3 肯德基 kfc)。
-
AC 自动机 fail 树 dfs 序下标的范围是 \(1\sim cnt+1\)!!!

浙公网安备 33010602011771号