Thinking and Thoughts
-
前传:千题计划
-
两个维度的限制问题——转化到平面上,考虑CDQ,KDT,树套树……
-
两个序列相对大小关系影响——转化为大小关系的01矩阵处理
-
可持久化Trie维护区间最大异或值,可以借此进行等等算法
如 CF1777F,利用分治算法和可持久化Trie维护最大的(区间最大值异或区间异或和)
分治区间,双指针扫,确定区间最值,利用Trie查答案
-
分治算法往往可以简化区间统计问题所需的数据结构难度
-
CF506D,对于同颜色的边所连接的路径之类的问题,考虑每种颜色单独处理
-
具有相同特征的东西一起处理,譬如同色,同层……
-
CF1463E,找出所有子数组mex值的mex,考虑依次加入 \(0\sim n\) 的数,即可判断是否存在一个区间mex等于 \(t\)。
-
CDQ分治维护凸包:左半区间按照 \(x\) 排序,右半区间按照 \(k\) 排序暴力DP即可
尤其注意决策点 \(x\) 相同等特殊情况,可以按 \(x\) 排序之后第二维度再排序,直接取 $x $ 相同最优的一个即可。
-
R18T6西湖寻梦,发现同层特征,即可对点按层数分类,虚树DP处理
-
求树上两两路径长度的期望值,等于求所有长度之和除以 \(n\choose 2\)
-
一个只包含1,2的数组,对于任意区间 \([l,r]\),在区间 \([l+1,r],[l,r-1],[l+1,r-1]\) 总存在一个区间满足 \(S[l',r']=S[l,r]-2\)
-
CF990G,莫比乌斯反演:
\(f(n)=\sum_{d|n}g(d)\implies g(n)=\sum_{d|n}f(\frac{n}{d})\mu(d)\)
\(F(n)=\sum_{n|d}^N G(d)\implies G(n)=\sum_{n|d}^Nf(d)\mu(\frac{d}{n})\)
通过莫比乌斯反演,可以将统计满足gcd限制的问题转化为满足约数限制的问题
例如设 \(f(n)\) 为满足 \(w(x,y)=n\) 的 \((x,y)\) 个数,\(g(n)\) 为满足 \(w(x,y)|n\) 的 \((x,y)\) 个数,则满足形式2.例如 \(w(x,y)\) 可以为树上 \(x,y\) 路径上边权的 \(\gcd\),可以有 \(g(n)\) 为把所有边权为 \(n\) 的倍数的所有边加进集合后统计连通点对个数。
-
分治法解决区间询问,CF1100F
具体方法是:设合并两端区间(可重复)的答案的复杂度为常数 \(t\)(一般是带log的东西),但插入一个元素复杂度仅为 \(g\),询问 \(q\) 个区间的答案,那么有:
1. ST表:\(O(nt\log n+qt)\)
2. 线段树:\(O((n+q)t\log n)\)
3. 分治法:将询问离线,分治mid,做前缀后缀值
接着对于每个符合的询问,合并相应的前后缀计算答案
总共 \(q\) 次合并,\(n\log n\) 次单插,复杂度 \(O(ng\log n+qt)\),一般而言 \(t=g^2\),无论是空间还是时间都吊打前两个。 -
要求求解一个严格单调序列 \(b\),但只方便做非严格单调
考虑转化为求解非严格单调序列 \(c\),满足 \(c_i=b_i-i\),然后再求解 \(b\) 即可
-
树上差分基础运用 link
Pro1:支持动态点亮/熄灭一个点,求路径上点被点亮的个数
- 本质上是路径求和问题,考虑维护根到各个点的点权和,这样点亮一个点 \(x\),即为整体 \(add([dfn_x,dfn_x+siz_x-1],1)\)
- 然后查 \(u,v\) 之间可以 \(ask(u)+ask(v)-ask(lca(u,v))-ask(fa_{lca(u,v)})\)
- 树状数组维护即可
Pro2:支持动态点亮/熄灭一条路径,求经过点 \(k\) 的被点亮路径条数
- 点亮路径 \((u,v)->add(u,1),add(v,1),add(lca(u,v),-1),add(fa_{lca(u,v)},-1)\)
- 查询 \(ask([dfn_k,dfn_k+siz_k-1])\)
- 注意两个情况 \(add\) 要套 \(dfn\)
-
\(dfn\) 在讨论树上路径的时候有极大帮助 link
树上路径 \((u,v)\) 被路径 \((x,y)\) 包含,有以下情况
- 当 \((u,v)\) 是条链的时候,\(x\in [dfn_u,dfn_u+siz_u-1],y\in [1,dep_s-1]\cup [dep_s+siz_s,n]\),\(s\) 是链顶的下一个节点,可以倍增求
- 当 \((u,v)\) 非链时,\(x\in [dfn_u,dfn_u+siz_u-1],y\in [dfn_v,dfn_v+siz_v-1]\)
- 由此,统计这个问题等价于二维数点
-
求一个矩形包含点数——容斥+CDQ+树状数组
-
求一个点被多少矩形包含——自底向上扫描线,树状数组维护当前 \(x\) 下 \(y_0\) 被几个矩阵包含
-
四边形不等式维护决策单调性时,遇到浮点数必须保留,因为需要它更新最优决策点
-
分治维护决策单调性时,\(calc\) 函数中两个指针维护 \(w(p,q)\),则计算过程两指针移动总次数 \(O(n\log n)\)。link
-
针对按照时间的删除插入问题,时间轴常常可以作为一个维度。
-
CF375D——dus on tree
-
dus on tree 思想:先递归处理轻儿子,然后暴力清空轻儿子,接着递归重儿子进行保留处理
-
dus on tree 性质:
-
根节点到任意一点的轻边个数不超过 \(\log n\) 条。
证明:考虑设 \(v\) 是 \(u\) 的一个轻儿子,必然有 \(siz_v\le \lfloor \frac{siz_u}{2}\rfloor\),则显然
-
由结论1,可得上述暴力清空算法,每一个节点最多被清空 \(\log n\) 次。
-
-
-
CF1578L Kruskal 重构树上DP
一定不要忘记Kruskal重构树是一颗二叉树,且除叶子节点全是虚点
这本质是一种合并信息的方式,主要是关于 按最小/大生成树顺序断边。
-
行列转化:CF1140F
涉及到有序二元组的操作问题,尤其是酷似连边性关系,可以抽象为二维平面上的点,然后行列分化为左右部建立二分图,原图点可以看作是二分图中的一条边。进一步引申,行和列可以抽象二分图的左右部,点 \((i,j)\) 看作连接 \(i,j\) 的边。
-
CF1707C ,关于DFS树的问题。
- 判定一颗生成树是原图点 \(u\) 的DFS树,当且仅当非生成树边全部是返祖边。
- 生成树形态确定时,非树边 \((u,v)\) 作为返祖边,当且仅当根节点处于:
- 若 \((u,v)\) 路径不是一条链,则 \(dfn_{rt}\in [dfn_u,dfn_u+siz_u-1]\cup [dfn_v,dfn_v+siz_v-1]\)
- 若 \((u,v)\) 是一条链,则 \(dfn_{rt}\in [1,dfn_s-1]\cup [dfn_s+siz_s,n]\cup [dfn_v,dfn_v+siz_v-1]\),其中 \(s\) 是 \(u\) 在 \(v\) 方向上的儿子。
- 由此,当生成树形态确定时,我们可以通过树上差分配合树状数组的技巧,求出每条边作为生成树根时候满足多少条边的限制,由此判断是否合法
-
二人博弈的一个小众套路,CF1099F,先预处理出一个人的最优决策,然后再模拟第二个人的决策过程。
-
CF868F,整体二分/分治维护最优决策点(决策单调性),需要计算 \(w(i,j)\),可以 \(O(1)\) 移动端点,可以考虑直接维护 \(w\) 的时候用莫队方法维护,可以证明在分治每一层中指针最多移动 \(O(n)\) 次。
-
强操作:一般遇到有后效性或者说需要用到以后状态的DP,可以考虑跑个一两百次逼近答案。CF24D
-
- 数据结构维护换根DP,譬如用线段树结合DFS序动态维护深度等信息。
- 规避删除的方案:当求min/max的时候,需要删除一些点(甚至有些点会重复删),可以仅仅考虑使得这些东西对答案无影响即可。譬如直接将其全部减掉inf
-
- ST表优化建图,适用于重复连边无影响的问题,如拓扑排序等。其严格强化版为DS优化建图。
- 步骤:
- 先建立 ST表维护序列,这样共有 \(O(n\log n)\) 个点,并且本层的节点连向下层的节点(本质类似于静态的线段树,但点数更多,效率更高)。
- 然后对于连边区间 \([l,r]\),则将其拆为ST上两个区间进行连边即可,必要时可以维护向上向下连边,总复杂度 \(O(n\log n)\)
- 扩展到树上——食用dfs序拍到序列上,对于路径的处理需要配合树链剖分,复杂度 \(o(n\log n)\)
- 可以维护向上向下两个分量,对于不可以连接自己的情况,可以在 \(add(l,r,x)\) 的时候特判,分为 \(add(l,dfn_x-1,x),add(dfn_x+1,r,x)\)。
- submission
-
连边,构建树本质上也属于匹配问题,也即网络流问题,网络流问题可以通过流量限制构建图的出度。例如:
CF277E,给定 \(n\) 个平面上的点,要求组合为一颗二叉树/链,使得边权和最小,边权和定义为两点间的最短路径距离,同时 \(i\) 作为 \(j\) 的父亲必须有 \(y_i>y_j\)。
可以通过网络流建模解决,这等价于每个点出度最多为2,每个点可以匹配 \(y\) 比它小的点最多两个,且带权,权值为两点欧几里得距离,求最小权完美匹配即可。具体的,把所有点拆为出入两份,对于每个点的出点向所有 \(y\) 比自己小的入点连边,容量1,费用为欧几里得距离,源点向每个出点连边,费用0,容量2,每个入点向汇点连边,容量1,费用0,进行最小费用流即可
-
前缀线性基
考虑对于原序列的每一段前缀,维护一个前缀线性基。
对于每个二进制位,维护可以贡献它的基底中下标最大的一个。
插入的时候如果存在基底,考虑将插入的数和基底中下标较小的一个继续向下插入,另一个作为当前位的基底。
查询只需要第 \(r\) 个前缀线性基中下标大于等于 \(l\) 的基底。
- 高维二项式反演,只要对于每一维,都可以进行二项式反演(假定其他维度已经确定),那么可以高维二项式反演
下面以三维为例,可以任意扩维
\[g(n,m,k)=\sum_{a=0}^n\sum_{b=0}^m\sum_{c=0}^k{n\choose a}{m\choose b}{k\choose c}f(a,b,c) \]\[\implies f(n,m,k)=\sum_{a=0}^n\sum_{b=0}^m\sum_{c=0}^k{n\choose a}{m\choose b}{k\choose c}(-1)^{a+b+c}g(a,b,c) \]同理有:
\[g(n,m,k)=\sum_{a=n}^N\sum_{b=m}^M\sum_{c=k}^K{N\choose n}{M\choose m}{K\choose k}f(a,b,c) \]\[\implies f(n,m,k)=\sum_{a=n}^N\sum_{b=m}^M\sum_{c=k}^K{N\choose n}{M\choose m}{K\choose k}(-1)^{a+b+c-n-m-k}g(a,b,c) \] -
连通块DP & CF1515E
-
在构造局部方案时,可以考虑打表辅助构造。
-
bitset优化01背包可行性问题。
-
考虑一个ex:利用bitset得到 \(f_{i,j}\) 表示在拼出 \(i\) 的情况下能否拼出 \(j\)。
有方程:
f[0][0]=1; for(int i=1;i<=n;i++){ for(int j=d;j>=0;--j){ if(j+a[i]<=d)f[j+a[i]]|=f[j];//bitset f[j]|=(f[j]<<a[i]); } }
-
-
高维前缀和——子集和-结合Min-Max容斥等
for(int i=0;i<n;i++){ for(int j=0;j<(1<<n);j++){ if((j>>i)&1)f[j]+=f[j^(1<<i)]; } } -
随机 \(n\) 个值域为 \([0,2^k-1]\) 的数进行异或得到 \(0\) 的概率是 \(\frac{1}{2^k}\)
证明:
考虑第 \(bit\) 位,显然它是一是零有 \(\frac{1}{2}\) 种可能。所以即证。
由此,我们会得到一些应用。譬如判断某个数出现了奇数次,可以对这些数离散化,然后利用 mt19937 随机赋权进行异或 Hash。
例:CF1479D,多次询问 \((u,v,l,r)\),求树上 \((u,v)\) 路径上点权出现次数为奇数的点权最小值。
按照点权离散化,然后给每一个权值赋一个随机值,记得是64位的。开一颗主席树进行DFS预处理。第 \(u\) 颗树维护前 \(i\) 种值(按照大小)的异或和。
查询的时候找到 \(lca,fa_{lca}\),判断子树 \(a,b,c,d\) 维护的值存在出现次数为奇数,当且仅当 \(s_a\oplus s_b\oplus s_c\oplus s_d\neq 0\)
类似题。
-
排列 \(p\) 的研究,可以转到平面视作点 \((i,p_i)\) 进行研究 CF1909F1/2,也可以连边 \((i,p_i)\) 得到若干简单环进行研究。
-
非一般地DP优化策略与视角。考虑DP时候比较 \(f_i-f_{i-1}\) 的值的差异进而放缩到 \(f_i-f_k\) 的差异 与 \(w(i,k)\) 的关系进行优化决策。如 CF1768F
-
势能分析复杂度。一个数每次减少一半,最多会减少 \(\log x\) 次。
可以用于数据结构复杂度分析。
一类基于值域的数据结构,类似于平衡树。例子:
支持以下操作:
- 将全局大于等于 \(x\) 的数全部减去 \(x\)。
- 求每次减去了多少个数/查询每个数被减去了多少次
可以用平衡树维护它。每一次拿出 \(\ge x\) 的子树,然后将 \([x,2x)\) 的数单独拿出暴力重构,再把剩下的 \([2x,\infty)\) 的数直接打标记。
均摊复杂度:\(O(n\log n+\sum \log n\times \log a_i)\)
-
匹配视角:将数列 \(A_i\) 经过某些变换变为 数列 \(B_j\),可以看作上下两行的 \(i\to j\)。加以DP处理。
-
\((1,-1)\),括号序列与折线图
可以将一个 \((1,-1)\) 序列用折线图的方式表达。
限定前缀和:考虑一个任意的 \((1,-1)\) 序列,都可以用 \((1,1,1,\dots -1,-1\dots)\) 插入 \((-1,1)\) 来表达。
且插入一个 \((-1,1)\),使得前缀和多出现一个 \(s_i -1,s_i\)
-
DP 维护 DP 问题。
维护两个DP,一个是正着的答案,这有一个DP更新模型。
然后我们再维护一个DP,表示维护题目所给操作的贡献。
-
唯一排列判定问题。
判断是否存在唯一排列 \(p\),使得 \(l_i\le p_i\le r_i\)。
经典:贪心思想:按 \(1\sim n\) 填入 \(p\),用堆维护可填位置,并贪心选择 \(r\) 最小的位置填进去。
判断唯一:一个排列在某些限制下唯一存在,当且仅当不存在两个数 \(i,j\),\(swap(p_i,p_j)\) 后该排列仍然符合条件
因此可以得到关于 \(j,l_j,r_j\) 的范围限制,数据结构维护即可。
-
DP 维护 DP 问题。
题目形如:有多少个 \(S\),满足 \(S\) 与给定的 \(T\) 符合某种要求。
如果我们可以将这个要求用动态规划匹配的方式刻画出来,那么我们就可以设状态为该动态规划算法的维度及其答案。
-
括号序列匹配类DP问题。——将左括号看作 +1,右括号看作 -1.
求符合要求的括号序列的方案数(可能附加概率期望)。
可以看作插入 \(()\),\()(\) 进行转移。
同样如果只是在一段插入,可能导致插入 \()(\) 不合法,所以可以设 \(f_{n,x}\) 为在序列前面还有 \(x\) 个 \((\),长度为 \(n\) 的满足要求的括号序列个数。
这样可以避免 \(-1\) 导致的括号序列不合法。
简单来说,要处理DP的限制条件,可以考虑附加维度进行条件提供以避免限制。
-
动态规划设计问题:若求恰好 \(x\) 个的答案,不妨求 \(f_x\) 为至多 \(x\) 个的答案, \(ans_x=f_x-f_{x-1}\)。
这样的DP难度往往更小。
-
最小斯纳坦树问题——最小生成树问题扩展 P6192。最短路结合状态压缩DP。
-
P7381,有后效性与特殊性的图上DP问题。
可以考虑找特殊点/边,比如边权最大最小值,度数为1/2 之类的点/边,先优先确定其DP值,然后进行拓扑排序从而消去后效性。
-
线段树合并优化DP。
用于例如给定 \(n\) 个点,\(c_i\) 为点 \(i\) 的颜色,……。
若DP只关心在子树内出现过的颜色。可以考虑使用线段树合并优化。
我们在线段树合并向下递归的过程中可以维护类似于前缀和,后缀和之类的信息以辅助DP。
-
在一个长为 \(n\) 的排列 \(p\) 中,任意 \(i\) 个数 \(a_1\sim a_i\),\(a_1\) 在 \(a_2\sim a_i\) 前出现的概率是 \(\frac{1}{i}\)
进一步地,任选 \(i\) 个数出现在另外 \(j\) 个数之前的概率是 \(\frac{i!j!}{(i+j)!}=\prod_{k=1}^i \frac{k}{j+k}\)
-
CF1032F:匹配为选出一条边,边的两个端点两两匹配,一棵树存在 唯一最大匹配 方案,当且仅当 \(n=1\) 或者该树存在完美匹配。
-
树的最大独立集个数下界是 \(\lceil\frac{n}{2}\rceil\)
-
CF1280D,将树划分为 \(m\) 个连通块,使得点权非负的连通块个数最大
在选出块数相同的情况下,根节点所在块的权值越大一定越优。
所以设 \(f_{i,j},g_{i,j}\) 为将子树 \(i\) 划分为 \(j\) 个连通块,最多有 \(f_{i,j}\) 个非负,且 \(g_{i,j}\) 为此时 \(i\) 所在连通块的最大权值和。然后转移就行。
发现一个图同一个SCC/VDCC/EDCC的点答案相同,则缩点,然后树形DP解决
一个EDCC/VDCC一定可以通过给边定向变为一个SCC,而一个SCC若将把边的方向去掉,一定可以变成一个EDCC
关于树上路径上出现偶数个相同的 \(a_i\) 的方法:随机赋权,然后做 xor。
对于树上 \(a_0\sim a_{m-1}\) 个点,按照 \(dfs\) 序排序后,最小的连通子树包含这些点的大小为 \(\sum_{i=0}^{m-1}dis(a_i,a_{i+1 \bmod m})\) 的一半。
经典计数题
滚动Trie树:也即动态维护当前这一层的Trie,动态维护下一层的 Trie,可以将空间优化到 \(O(n)\),缺点是必须批量一次处理所有询问。
for(int i=1;i<=n;i++)lst[i]=id[i]=1;sort(d+1,d+n+1);
int ans=0;
for(int bit=62;bit>=0;--bit){
for(int i=1;i<=n;i++)siz[i]=s[i][0]=s[i][1]=0;
int num=0,res=0;
for(int i=1;i<=n;i++){//lst i 表示自己所指向的链的最后一个节点的编号
int &t=s[lst[i]][(d[i]>>bit)&1];//填0
if(!t)t=++num;//建立Trie下一层的点
++siz[t];lst[i]=t;//
}
for(int i=1;i<=n;i++)res+=siz[s[id[i]][(d[i]>>bit)&1]];
if(res>=k){
for(int i=1;i<=n;i++)id[i]=s[id[i]][(d[i]>>bit)&1];
}
else {
for(int i=1;i<=n;i++)id[i]=s[id[i]][((d[i]>>bit)&1)^1];
k-=res,ans|=(1ll<<bit);
}
}
按位处理,DP计数,合并答案。
-
\([1,10^5]\) 的数,约数个数最大值 \(128\),\([1,10^6]\) 的数,约数个数最大值 \(240\),\([1,10^7]\) 的数,约数个数最大值 \(448\),\([1,10^8]\) 的数,约数个数最大值 \(768\)。
区间 \((l,r)\) 的查询也可以看作矩形 \((1,1,l,r)\) 的查询
一个区间 \([l,r]\) 是好的,当且仅当 \(\exists k\in[l,r),\max[l,k]<\min[k+1,r]\),可以考虑不断加入 \(1,2,…\),那么一个区间是好的,当且仅当存在一个时间点,满足 \([l,r]\) 由一段一和一段零拼成。所以可以使用线段树/并查集维护连通块,然后每次扔进去一个数,就会形成新的0段,1段,这样就可以得到一个范围 \(l\in [l_1,l_2],r\in [r_1,r_2]\) 的区间合法,那么这就变成了一个二维数点了。
结论:给定 \(a_1\sim a_n\),设已经从大到小有序。
那么 \(\min_{i,j\in [1,n]}a_i|a_j\) 取得最小值的 \(p,q\),必然满足 \(p,q\le \log V+1\),证明可以考虑数学归纳法。
树上统计,分类讨论好题。
当求出一条满足要求的路径的方案数时,若涉及到两条路径的合并操作,而这时候需要选出两条路径的方案,所以可以大胆设 \(f_{i,j}\) 为子树 \(i\) 选出 \(j\) 条路径的方案数。
- CF480E,经典问题。给出矩形,每次都将一个点从白色变成黑色,求操作后最大的白色正方形大小。\(n,m\le 2000\)。
重要操作:注意到答案上界是 \(n\),所以倒序操作后每一次可以 \(O(n)\) 去判断当前答案是否可以加一,复杂度均摊正确。一个点变成可选之后新的可能的答案只会经过这个点。
-
gym103049G,当计算期望的时候需要用到某一项未知的值,可以考虑二分这个值进行计算,然后调整。
-
CF1815D,定义集合 \(S=\lbrace x\oplus (n-x)|x\in [0,n],x\in Z\rbrace\),求 \(\sum_{t\in S}t\),按位填,设 \(f_{i,0/1},g_{i,0/1}\) 为当前位是否有来自前面的进位的和以及方案数。
-
前缀 \(or,and,\gcd\)至多有 \(log V\) 个不同值
-
link 利用斯特林数将 \(\sum w_i^k\) 转化为对组合数的求和问题。
-
link 斯特林反演常见使用场景:至少/至多连通块到恰有。
考虑设g_{i}为将原图划分为至少i个连通块的方案数(钦定 \(i\) 个),
一个实际 $k $ 连通块的图被 \(i\) 计数了——\(i\) 划分 \(k\)子集也即 \(S2(k,i)\)
设 \(f_i\) 为原图只恰存在 \(i\) 个连通块的方案
则根据 \(g\) 的意义有
\(g_i=\sum S2(k,i)f_i\)
那f_1!
\(f_1=\sum (-1)^{i-1}*S1(i,1)*g_i\)
-
多项式进行操作的时候不要忘了把无用的位置清零
-
link 计算数列通项公式时涉及 \(\sqrt 2,\sqrt 3\) 这些别再傻傻矩乘了,直接二次剩余找到对应逆元即可。
-
CF452F 判断排列中是否存在等差子序列,其实也相当于是判断数轴上是否存在三点,关于中间点对称。直接枚举中间点,如果不对称当且仅当存在 \(a_i-k,a_i+k\) 出现状态(是否出现在左边)不同,则直接哈希01串判断是否回文。
-
对于任意三个非负整数 \(x,y,z,x+y+z=n\),\(x\oplus y\oplus z\) 所有取值与 \(n\) 奇偶性相同且都可以取到,详细的是 \(x\oplus \frac{n-x}{2}\oplus \frac{n-x}{2}\),又因为 \(x\oplus y\oplus z\le x+y+z=n\),所以都可以取到。
-
CF1452B 简化技巧:对于 \(\sum a_i=s\) 的正整数 \(a_i\) 来说至多有 \(2\sqrt s\) 个不同的值。
本题中要枚举每一种值作为末尾的方案,单个数加入DP的复杂度是 \(O(s)\),则我们先把这些不同的 \(s\) 每一个都拿出来,然后把剩下的重复的全部先加入DP数组,接着依次处理这 \(O(\sqrt s)\) 个,每次用 \(O(s\sqrt s)\) 去更新,记录这个值的贡献次数即可。复杂度 \(O(s^2)\)
-
\(n=1e6\) 时,
for(int i=1;i<=n;i++)for(int j=i;j<=n;j+=i)for(int k=j;k<=n;k+=j)只会执行 \(10^8\) 左右次。CF1946F,利用该性质计算增量。以 \(a_l\) 为开头,\(a_r\) 为结尾的子序列个数,满足前一项是后一项的约数,可以暴力直接计算。 -
CF1208F \(a_i|(a_j \& a_k)=(!a_i)\& a_j \&a_k+a_i\),而求 \(a_i\& a_j\& a_k,i<j<k\) 的最大值可以考虑高维前缀和预处理超集的下标最大值,次大值,然后贪心枚举 \(a_i\&a_j\&a_k\) 的下一位是否可以填 \(1\),\((res|(1<<i)\) 的超集下标次大是否大于 \(pos\))
-
CF1651F 将相邻两个 \(1\) 变成 \(0\),或者将相邻两个 \(0\) 变成 \(1\),可以转化为对奇数位先异或 \(1\),变成 \(01\to 10\) 这种善于处理的类型
-
CF1620F 二分图是不存在奇环的图,DP优化经典问题:给定数列,可以自主选择是否将 \(a_i\) 改为 \(-a_i\),求问是否可能使得序列的最长下降子序列不超过 \(2\)。
暴力的设 \(f_{i,x,y}\) 为前面 \([1,i]\) 最大值为 \(x\),而有一次下降的末尾最大值是 \(y\) 是否可能。
然后对于状态 \((i,x,y)\to (i+1,p,q)\),必须有新加入的数 \(t\ge y\)。根据定义判断即可
然后考虑优化状态,比较决策,一方面可以看到 \((i,x,y)\) 与 \((i,x,y-1)\) 相比前者必然更强,所以又可以更改状态为 \(f_{i,x}\) 为 \(y\) 合法的最小值。同理 \(y\) 相同的时候 \(x\) 也是越大越优。然后转移的时候取 \(max\)接着继续考虑优化状态,观察状态转移,可以看到设新加入的数是 \(now(now\in\lbrace a_i,-a_i\rbrace)\),状态是 \((x,y)\)
可以得到:\(now>x:(x,y)\to (now,y),now<x:(x,y)\to (x,now),now>y\),进而又可以发现两个维度中经过转移至少可以保留一个维度不变,亦或者说合法转移的情况下 至少有一个维度是与 \(now\) 相同,所以又可以设置为 \(f_{i,0/1,0/1}\) 为 \(x/y\) 等于 \(a_i/-a_i\) 时,另一个的最小值。
给无向图定向问题:
对于一个 \(EDCC,VDCC\),都满足存在至少一种定向方式使得这个分量可以变成 \(SCC\),这是耳分解,而如果是两个点之间存在不能经过重复点的道路则只能是点双满足。
- CF842E 树的直径与树的直径中点转化:
对于一颗树,每次新增一个叶子节点,问每次加点后有多少点可以作为直径端点,其实条数也可以维护。
树的直径中点在每次加入叶子节点最多移动一个位置,可能移动到边上,亦可以通过技巧使得每次加入一个长为 \(2\) 的链来保证直径只能移动到点上。
所以可以转化为线段树最大值个数问题。当最大值唯一的时候就考虑移动端点。
- CF1606F 动态维护决策树
多次询问,删除一个节点 \(u\) 后,\(u\) 的子节点会成为 \(u\) 父亲的子节点,每次给定 \(v,k\),求 \(c(v)-mk\),\(c(v)\) 是 \(v\) 操作后子节点个数,\(m\) 是删除节点个数。
决策树,转化问题,删除点,将子节点接到父亲上,可以转化为赋权的连通子图问题,也就是不真正删点,只是将这个点点权归为 \(0\),那么子节点个数其实也就是以 \(v\) 为根,由周围的 \(0\) 点围起来的连通分量。而叶子节点个数其实是可以用度数和节点个数推出来。那么这就是一个赋权的问题了
问题可以转化为给定有点权的树,每次询问给节点 \(u\) 子树内所有点点权减去 \(k\) 后包含 \(u\) 的最大权连通子图。我们建立转移虚树,而随着 \(k\) 的减小加入新的决策,进而不断影响祖先最后求的答案
不断减小k,令w=-k
若f_u>=0,则虚树上建立边(u,fa_u)
这条边存在当且仅当目前虚树上siz[u]*w+s[u]>=0---->w>=(-s[u]+siz[u]-1)/siz[u]
因此开个堆,把当前虚树森林上各个根扔进去,然后逐步减小k的过程中,我们反复取出,然后更新,然后再插进去,用并查集维护这个根的关系,注意到每取出一次说明更新了一条边,则最多取出n次,复杂度O(nlogn)
然后对于查询,我们只需要知道当前虚树森林某个点的siz和s,而注意到合并过程在原树上等价于链加单点差,woc!
这东西直接DFS,然后树状数组弄即可
经典题目
-
对于一个由 \(1,-1\) 构成的序列 \(a\),如果其总和 \(\ge 0\),必然可以从某个 \(k\) 开始绕环走一遍使得其前缀和不存在 \(<0\) 的位置,具体取前缀和最小的后面那个位置开始即可。
-
线性基在图上的性质 CF724G
对于一个无向连通图,有边权,构建 DFS 树后,将所有环的权异或组成一个线性基,具有以下性质
- 这个线性基只需要所有返祖边所对应简单环异或和即可构建
- 点 \(u\to v\) 的所有可能的路径的异或值均可以用这两者的简单路径的异或值与线性基中的值表出,这是因为走到一个环又走回去是可以抵消的,这时候产生贡献的只有环。
- 对于 \(u\to v\) 所有路径的异或值,用 \(B\) 表示线性基,则有 \(d_u\oplus d_v\oplus B\)
-
线性基技巧:给定线性基 \(B\),设其基底大小为 \(S\),统计 \(\sum (k\oplus x)\),\(x\) 可以被 \(B\) 表出。同样是按位考虑计算。考虑二进制下第 \(w\) 位是否有数这一位是 \(1\),如果是那么这一位可以有 \(2^S\) 个取法(恰各有 \(2^{S-1}\) 个对应有没有 \(1\)),如果没有就只有 \(2^{S-1}\)。
-
计数综合——DP+莫比乌斯+群论 CF1954F *3100
-
陷入复杂的分讨误区时,不妨跳出看看,是否可以有更优秀的计算方法
-
CF1956F 两个维度的连通性问题。
每个数给定两个区间 \(L_i,R_i\),对于两个数有边,当且仅当 \((R_i\cap L_j)\cup (L_i\cap R_j)\) 不为空。求连通块个数。
考虑建立虚点,对属于的 \(L,R\) 都连边,同时满足两个条件的方案为满足其一的方案减去只满足一个的方案,然后将只满足一个维度限制的点删掉即可。
- 对于一个正整数序列 \(a_1\sim a_n\),每次可以选择一个长度至少为 \(2\) 的区间减去一个正整数,则最终序列可以变为全 \(0\) 的充要条件是:
设 \(a_0=a_{n+1}=0\),则有 \(\forall i\in[1,n],a_i\le a_{i-1}+a_{i+1}\)。
本题计数长为 \(n\),\([0,m]\) 的所有符合条件的序列个数。
模型:在 \(i-1\to i\) 的转移中,若可以求出这一步的所有方案(可能非法),则可以考虑容斥,亦即用满足 \([1,i-1]\) 的所有方案数减去 \([1,i-1]\) 全部满足,而唯独不满足 \(i\) 的方案数即可。
本题应用:设 \(f_{i,j}\) 为 \([1,i-1]\) 全部合法,\(a_i=j\) 的方案,则可以有 \(f_{i,j}=\sum_{t=0}^m f_{i-1,t}-g_{i,j}\),而 \(g_{i,j}\) 就是钦定 \(i-1\) 不合法,\([1,i-2]\) 全部合法的方案数,这可以由 \(f_{i-2}\) 转移。因为不等式限制不可能算重。\(i\) 不合法则 \(i+1,i-1\) 一定合法。
- CF1948G 最大匹配等于最小点覆盖,可以把对最大匹配的限制转化为最小覆盖。
本题:\(n\le 20\),求权值最小的生成树,生成树权值定义为边权和加上 \(k*c\),其中 \(k\) 是常数,\(c\) 是最大匹配数。
则可以枚举最小点覆盖集合,得到可用边,再用它做最小生成树即可。
- 转化视角:区间 \([l,r]\) 可以视作点 \((l,r)\),则包含点 \(i\) 的区间 \([l,r]\) 的子区间可以用矩形 \((l,i)->(i,r)\) 来表示,可以利用它做到对 \(min/max\) 对区间进行标记,利用扫描线解决问题。
- 对于区间分治,\([l,mid],[mid+1,r]\),枚举 \(i\in [l,mid]\),则统计跨过中点的答案时,设 \(j\) 为右端点,则必有 \(p,q\),满足:
- \(j\in [mid+1,p]\),则 \(min,max\) 全部在 \([i,mid]\) 出现
- \(j\in [p+1,q]\),则 \(min,max\) 在 \([i,mid],[mid+1,j]\) 中一边一个
- \(j\in [q+1,r]\),则 \(min,max\) 都在 \([mid+1,j]\) 中。
满足性质:\(i\) 递减时 \(p,q\) 单调不降
- CF1842G 关于乘法拆分的问题 组合计数题
- 没用的时候不区分,用的时候再标号,系数用到了再算
- 有关乘法分配律 —— 每个乘上去的多项式都是选一项产生贡献,可以考虑其组合意义,也可以考虑其合并同类项、
- CF914F 分块SAM,本质是对多次询问字符串长度的根号分治。也即对每个块建立SAM
- \(len\ge \sqrt n\),则直接暴力建立相应询问区间 \([l,r]\) 的 SAM 直接算,总复杂度 \(O(n\sqrt n)\)
- \(len\le \sqrt n\) ,则只可能出现在一个块内或者跨越两个块,一个块内的答案直接在每块直接找,然后边角暴力。对于跨越两个块,则从交点向左向右各扩展 \(len-1\) 长度直接扫。复杂度 \(O(n\sqrt n)\)。
- 经典划分问题:
给定 \(a_1\sim a_n\),每次可以选出最多 \(m\) 个数减去一,求最少操作次数使得其变为全零。
\(ans=\max(\max a_i,\lceil\frac{\sum a}{m}\rceil)\)
证明:取前者是显然的,每次先取一个最大值,然后化为剩下的 \(a\) 与 \(m-1\) 的子问题。
取后者:考虑设后者的值为 \(k\),从时间轴的角度来看
下界显然,现在说明一种构造方案。
我们假设在每一个时刻都有一个烙饼,最多将其划分为 \(m\) 份,分给 \(n\) 个人,每个人最终要有 \(a_i\) 块烙饼。按照 \(a\) 从大到小排序。
我们考虑每个人在哪个时刻可以拿到烙饼,假定有一张表:
由于 \(k\ge \max a_i\),所以我们从最底层开始填,依次填上 \(1,2,3,…,k\),然后轮回重复。最后一次写到多少算多少。
这样我们就给出了每个人在什么时候拿烙饼的分配方案,同时也显然保证了每一时刻最多切出 \(m\) 份烙饼。
经典结论:对于无向带边权连通图,任取一颗生成树,则 \(u\to v\) 的所有路径(可以是非简单路径,可以一条边反复走)长度一定满足 \(dis \equiv k(\bmod gd)\)
其中 \(gd=\gcd(2w,w_{cir})\),也就是所有环长以及每一条边长的两倍的 \(\gcd\)。同时,所有环可以被表示为简单环的组合,也就是我们只需要考虑所有非生成树边与这棵树形成的简单环的长度即可。
类似的,边权的 \(xor\) 借助线性基也可以这样表示。参见 CF724G
对于时间相遇之类的含参问题,可以直接建立函数模型
对于在一定区间 \([l,r]\) 内判断两单调曲线 \(f,g\) 是否有交点
可以直接看作直线,也就是 \((f(l)-g(l))(f(r)-g(r))\le 0\)
经典问题:将一棵有根带点权树染色,根节点最初已染色,一个点的染色时间必须晚于父节点,\(t\) 时刻染点 \(i\) 代价是 \(t\times w_i\),求染色顺序使得总代价最小
贪心:当前点权最大点必然在其父节点染色之后立刻染色
所以合并这两个点,新的点权设为 \(\frac{a+b}{2}\)。
不断合并,新的点权就是组成这个点的所有点的点权平均数。
线段树一个点维护 \(a_i,b_i,c_i\) 等多个向量,涉及到多个懒标记维护
可以考虑将一个节点需要维护的信息设为一个一维向量,将转移信息表示为矩阵,这样懒标记就是矩阵,适当将常数,区间长度等设为辅助信息,更新 \(lz\) 为 \(lz\times mat\)。
无需考虑转移顺序,因为矩阵就是转移。这方法相当通用,就没必要分开懒标记而考虑懒标记顺序。尤其是涉及到需要维护多个数组互相转移的信息。
周期性变化,时间变化——将时间与位置建轴,这样是一条线。也可以将出现时间与位置建图,这样是一个点,然后运动轨迹是线
数形结合。求类平行四边形矩形里的答案。如果斜率确定,可以变换点坐标 \((x,y)\to (x,x+y),(x,y)\to (x,y-x)\)。这是斜率为一或负一的情况。
- 网络流
残量网络(只考虑仍有容量的边),是一个有向图
考虑必经点,必经边,可行点,可行边
跑一边强连通分量,SCC的意义是(一个环,从T到S的路表示这一条增广路填满,而从S再到T是表示另一个决策,可以替代)则连接两个SCC的边是必经的(两个端点不在一个强连通分量中,就是说没有一条从一个端点到另一个端点的增广路,也就是说这条边是无可替代的。)
必经边的端点是必经点。且从S出发走cost=1的边达到的X部点是所有的非必经点,从T出发走cost=0到达的Y部点一定是所有的非必经点
可行边:要么在当前求出的匹配里,要么在同一SCC里
可行点:可行边以及必经边的端点。
-
String and Gcd \(\sum_{d|n}\varphi (d)=n\) 可以用于:\(\gcd(a,b)=\sum_{d|a,d|b}\varphi(d)\)
-
CF1978F & 悲哀 关于 \(\gcd(a,b)>1\) 的点对统计,可以将每个 \(value\) 只保留质因子的积,极大程度简化约数个数。
-
CF1290C 利用并查集维护决策集合。
形式的说,建立绝对正确,绝对错误,以及扩展域并查集,这样可以做到在增加相关关系的过程中维护三类命题:绝对正确,绝对错误,以及未知正误,同时维护其相关逻辑关系。
-
方格染色 和 [疯眼] 有些相似。将01矩阵的每行每列视作未知元,一共 \(n+m\) 个。研究 \(a_{i,j}\) 的值是否与 \(a_{i,0},a_{0,j}\) 有关。建立图的关系。一般来说存在 \(a_{i,j}\oplus a_{i-1,j}\oplus a_{i,j-1}\oplus a_{i-1,j-1}=t\) 这种关系肯定是有关的。
-
线段树维护树的直径,O(1)LCA,两颗虚树合并后其直径两端点必是原两条直径端点之二。
-
CF1149C 线段树维护树的括号序列的直径
-
结论1:括号序列中第 \(l\) 项与第 \(r\) 项之间的距离是 \(r-l+1-2mac\) ,其中 \(mac\) 是匹配括号对数。
-
结论2:一个括号序列 \([1,m]\) 其总长度-最大匹配括号对数*2为 \(\max_{k\in [1,m]}(S_m-2S_k)\)
可以理解为 \())))((((\) 必然存在一个断点,使得没有匹配括号跨过它
-
结论3:括号序列 \([1,n]\) 中的直径是 \(\max_{L\le x\le R}(S_R-S_L-2(S_x-S_L))=S_R+S_L-2S_x\)
考虑线段树维护这个值
合并区间的时候,只需要处理 \(L\in [l,mid],R\in [mid+1,r]\) 的情况,枚举 \(x\) 在哪一边,维护 \(mxl=\max S_{L}-2S_x,mxr=\max S_R-2S_x\)
需要前缀最大值,前缀最小值,和辅助计算。
void pushup(int x){ s[x]=s[lc]+s[rc]; ln[x]=min(ln[lc],ln[rc]+s[lc]); lx[x]=max(lx[lc],s[lc]+lx[rc]); mxl[x]=max(mxl[lc],max(mxl[rc]-s[lc],lx[rc]+s[lc]-2*ln[lc])); mxr[x]=max(mxr[rc],max(mxr[lc]+s[rc],s[rc]-2*ln[rc]-(s[lc]-lx[lc]))); mx[x]=max(max(mx[lc],mx[rc]),max(mxr[lc]+lx[rc],mxl[rc]-(s[lc]-lx[lc]))); }
-
-
树的括号序列相关性质
- 若从序列中任取一段连续子序列,从中去掉所有匹配括号后,剩下的括号组成的路径一定为一条链,链长为剩下的子序列长。
- 树上直径长度即为任意区间去掉匹配括号后的长度的最大值
- 最长去匹配区间 = 最大的(将区间分成两段)后面的权值和 - 前面的权值和(左括号1,右括号-1)
平衡树维护矩阵乘法转移DP,类似树形DP维护
fhq_treap可以动态维护笛卡尔树结构,例如CF1988E。
二维矩形计数:可以固定某一边然后扫描
-
笛卡尔树结论 \(max(A)+min(A)>len(A)\) 的最长子段。建立 \(min\) 笛卡尔树,然后贪心取整颗子树里的 \(max\) 与其最长区间取 \(min\) 一定是对的。
-
根号分治思想不仅用于算法,也可以用于分析状态数目。例如雅加达的摩天楼
-
P5304 按位分治,次短路。
经典结论:对于排列 \(P\),每次只能给 \(|P_i-P_j|\le 1,|i-j|\ge k\) 的两个数交换位置,则可以得到的所有新的排列 \(Q\),满足 \(\forall 1<|i-j|<k,(P_i-P_j)(Q_i-Q_j)>0\)。(利用逆排列进行研究)
- 拓扑排序最小字典序问题。
小的尽量靠前。建立正图,用优先队列,每次取出编号最小的赋值。\(1\to n\)。
靠前的尽量小。这是最小化字典序,那么我们建立反图拓扑排序,每次取出编号最大的点赋值为 \(n\to 1\)。
其实是最小化 \(f_{i}\) 与 \(g_{f_i}\) 的区别。
-
两个有公共边的奇环一定组成一个偶环。一个VDCC/EDCC/SCC若存在奇环,则所有点都在奇环中。
-
精准预测 。虽然感觉不应该评黑。在空间限制下,可以考虑分块计算答案,这样空间会从 \(O(f(N))\) 变为 \(O(f(B))\),时间乘上 \(O(\frac{N}{B})\)。2-SAT 两个点可以同时取 \(1\) 的充要是两个点本身不是必不取(也就是可以推到取 \(inv\))同时不能互推不能取。
- 手写BITSET
```cpp
struct bet{
ull num[5*(N>>6)];
bet(){
memset(num,0,sizeof num);
}
bet(const bet &tmp){
memcpy(num,tmp.num,sizeof num);
}
void reset(){
memset(num,0,sizeof num);
}
void set(int pos){
num[pos>>6]|=1ull<<(pos&63);
}
void shift(){
ull lst=0;
for(int i=0;i<up;++i){
ull tmp=(num[i]>>63);
num[i]<<=1;num[i]|=lst;lst=tmp;
}
}
int count(){
int res=0;
for(int i=0;i<up;i++)res+=__builtin_popcountll(num[i]);
return res;
}
bet& operator=(const bet &tmp){
memcpy(num,tmp.num,sizeof num);
return *this;
}
bet& operator&=(const bet &tmp){
for(int i=0;i<up;i++)num[i]&=tmp.num[i];
return *this;
}
bet& operator|=(const bet &tmp){
for(int i=0;i<up;i++)num[i]|=tmp.num[i];
return *this;
}
bet& operator^=(const bet &tmp){
for(int i=0;i<up;i++)num[i]^=tmp.num[i];
return *this;
}
friend bet operator-(const bet& a,const bet& b){//a-b
ull lst=0;bet res;
for(int i=0;i<up;i++){
ull cur=(a.num[i]<b.num[i]+lst);
res.num[i]=a.num[i]-b.num[i]-lst;
lst=cur;//这个自然溢出好神奇,自动补位
}
return res;
}
}
-
市场 对于定值 \(k\),\(f(x)=x-\lfloor\frac{x}{k}\rfloor\) 单调不增。所以维护区间的 \(\min,\max\) 即可做到维护 \(a_i\leftarrow \lfloor\frac{a_i}{d}\rfloor\) 操作。
-
CF1988F·典 二维FFT计算,可以将列扩展两倍,然后拍成行进行 FFT。适用于计算: \(F(n,m)=\sum_{i,j}A(i,j)\times B(n-i,m-j)\)。
升高与前缀最大值个数的DP:设 \(f_{i,j,k}\) 为 \([1,i]\) 的排列,有 \(j\) 个前缀最大值和 \(k\) 个升高。有 \(f_{0,0,0}=f_{1,1,0}=1\),其余考虑插入 最小值。
-
CF1988E·典:二叉树中,考虑这样的链:每个点的左儿子作为开头,后面一直沿着 \(rc\) 走,则这样的链之和大小是 \(O(n)\),理由是每个点最多有一个这样的祖先让其属于这条链。本质是一种不重不漏的链剖分
-
CF1989F 动态加边,维护图强联通分量。离线之后利用整体二分做。二分每条边所两个点成为SCC的时间。
关键在于重标号,保证复杂度。
code
void sol(int l,int r,vector<int>nowv,vector<int>nowe){
for(auto u:nowv)w[u].clear(),w[u].shrink_to_fit(),dfn[u]=low[u]=vis[u]=col[u]=0;num=top=scc=0;
for(auto i:nowe){
if(i>r)continue;
auto [u,v]=e[i];
u=find(u),v=find(v);
if(u==v)continue;
w[u].push_back(v);
}
for(auto u:nowv)if(!dfn[u])tarjan(u);
for(auto u:nowv)vis[u]=0;
vector<int>nv,ne;
for(auto i:nowe){
if(i>r)continue;
auto [u,v]=e[i];
u=find(u),v=find(v);
if(u==v)continue;
if(col[u]==col[v]){
ne.push_back(i);
if(!vis[u])nv.push_back(u),vis[u]=1;
if(!vis[v])nv.push_back(v),vis[v]=1;
}
}
if(l==r){
for(auto i:ne){
if(i>r)continue;
auto [u,v]=e[i];
u=find(u),v=find(v);
if(u==v)continue;
if(siz[u]>1)res-=1ll*siz[u]*siz[u];if(siz[v]>1)res-=1ll*siz[v]*siz[v];
merge(u,v);u=find(u);
res+=1ll*siz[u]*siz[u];
// cout<<" "<<l<<": "<<i<<"\n";
}
cout<<res<<"\n";return ;
}
int mid=l+r>>1;
sol(l,mid,nv,ne);sol(mid+1,r,nv,ne);
}
-
威尔逊定理:\(p\in\mathbb{P}\) 当且仅当 \((p-1)!\equiv -1(\bmod p)\)
-
- 每条重链链底都是叶子
- 每条重链自底向上维护一个单调栈,同时维护倍增数组表示扫到点 \(u\) 时单调栈中第 \(2^j\) 个是谁。整个单调栈可以通过 $\log $ 次操作还原。
- 上述信息可以维护且合法,还可以利用倍增数组维护更多信息
-
\[\begin{aligned} &A_i+A_j\le B_i+B_j\\ &B_i+B_j\le C_i+C_j\\ \implies& \\ &A_i-B_i\le B_j-A_j\\ &B_i-C_i\le C_j-B_j\\ \end{aligned} \]
维护二元组 \(<A_i-B_i,B_i-C_i>,<B_i-A_i,C_i-B_i>\) 转化二维偏序。
-
P6965 线段树优化建图的技巧同样可以应用于其他树形结构(Trie,平衡树等都可以)。树形结构的相通性
-
CF1994F 一棵树断边后奇度点与偶度点个数奇偶性不变。且在有偶数个奇度点时,可以将奇度点变为零个。具体的做一遍 DFS,在回溯时若还是奇度则断掉其与父亲的连边。根节点根据偶数个奇度点显然成立。
-
CF1994G 调整法应用:给定若干组物品,每个物品都有重量,现在要每组选出一个使得重量和为 \(s\)。可以考虑先将 \(s\) 减掉每一组的最小值,然后每一组自己也减掉最小值,问题可以变为每一组都最多选一个,选出 \(s’\) 的方案。本质还是拆贡献
-
- 矩阵乘法的本质就是在分层状态图上以固定策略走路
- \(c_{i,j}=|_{k=1}^m a_{i,k}\& b_{k,j}\) 此类扩展矩阵乘法可以用于维护可行性。(当然类似于 \(+*\) 矩阵乘法维护方案数(取质数模))
- 利用 \(|\&\) 矩阵乘法在环上转移的可行性(\(i\) 的决策涉及 \(i-1,i+1\))记录起始状态,走完一圈环后仍然回到 \(1\)。令起始状态与终止状态相同即可解决。
- 其本质还是将序列DP改写为了“区间”DP,进而转移。譬如设 \(f_{i,0/1}\) 为 \([1,i]\) ,\(i\) 选或不选的决策,转移若只与 \(i-1\) 有关,则完全可以将其改写,维护一个起始状态,这可以就可以方便的实现两段区间的答案合并了。(恰巧这个形式就是矩阵乘法形式,左边的末态为右边的初态,注意是左开右闭),由此利用线段树维护矩阵乘法就可以得到答案。并且如上述,还可以维护走完一圈的答案,令始末相同即可。
- 求在某些限制条件下的 $\max -\min $ 的最大/小值,经典方法的利用双指针,枚举最小值,并用指针维护当前最小的合法最大值,在最优性的限制条件下,每次 \(\min\) 增大,指针单调不降。
-
定义一个正整数序列 \(a\) 是好的,当且仅当存在 \((i,j,k)\),满足 \(a_i,a_j,a_k\) 可以组成三角形
则“最长的”非好的序列是斐波那契数列。并且若有 \(a_i\le 10^9\),则这个数列最多不超过 \(45\) 项。
同时设最长的非好序列的长度是 \(k\),则 \(k+1\) 中必然可以组成一对三角形,\(k+4\) 必然可以组成两对三角形(拿出一对后变成子问题)
-
- 齐肯多夫定理:任意正整数可以唯一写成若干斐波那契数之和,且满足不存在相邻两个斐波那契数。构造方法是从大到小贪心取。
- 考虑每个位置的单位元的贡献。譬如在这个问题中,在位置 \(i\) 的一个筹码可以在 \(i-1,i-2\) 同时变出一个筹码,则其贡献 \(f_i=f_{i-1}+f_{i-2}\) ,神似斐波那契
-
P10704 数论分块套数论分块的复杂度是 \(O(n^{\frac{3}{4}})\)
-
CF1789F 对于串 \(S\) 而言,一个循环了 \(k\) 次的子序列,将 \(S\) 均分为 \(k\) 份(最后一份不足不用管)后,其循环节必然是某一份的子序列。
证明:这个子序列有 \(k-1\) 个断点,将 \(S\) 划分为了 \(k\) 个部分,这等价于说明在 \(S\) 中选出 \(k+1\) 个点,且开头结尾必选,使得每两个相邻的点之间必然有至少一个均分点(开头结尾也是均分点),与端点重合不算。这相当于将 \(k-1\) 个均分点分到 \(k\) 个部分里面去,使得每个部分至少有一个,这是不可能完成的。
-
P7670 统计二进制下固定某些位后的数的权值和。
也就是给定二进制串,其中有些位置是
?,0/1中任选一个填进去。求所有填法所对应数的权值之和。
一个方法是爆搜,复杂度是二的问号个数次幂
一个方法是用高维前缀和,并且将原串的某些
1改为0容斥计算,复杂度是二的一个数次幂一个方法是高维后缀和,复杂度是二的零个数次幂
-
ARC135F 计算某些函数的前缀和,积性函数考虑筛法,一些与进制有关的函数尽情考虑二进制拆分,折半等技巧。
运用
lowbit的知识我们可以很容易将 \([0,n)\),拆分为 \(O(\log n)\) 个 \([c,c+2^i)\) 的区间。 -
选 \(i\) 则不能选 \(j\) ,可以同时推出选 \(j\) 则不能选 \(i\),这启发我们直接连边,这样每个合法方案就是一个独立集 link
-
满足冒泡排序次数刚好取到下界 \(\frac{1}{2}\sum_{i=1}^n|i-p_i|\) 的排列 \(p\) 充要条件是不存在长度 \(\ge 3\) 的下降子序列,证明显然
-
Dirworths 定理经典变形:
- 若最长下降子序列不超过 \(k\) 则原序列可以被划分为不超过 \(k\) 个不下降子序列
- 若DAG上最长路径长度不超过 \(k\),则DAG可以被划分为不超过 \(k\) 个独立集
-
将转移写成图,附带转移系数观察,找通项公式(找本质不同路径个数,利用乘法交换律)
-
AGC040E 观察DP式(尤其是最优性DP),若发现DP值域很小且连续,则可以只维护断点
-
答案有凸性可以用闵可夫斯基和进行转移。(事实上可以用闵可夫斯基和优化带凸性的DP,详见 link)
-
link 根据二进制的方法,我们维护每个位置出现次数的奇偶性,则设当前变量为 \(x\),维护当前走到了二进制位 \(k\),当 \(x+1\) 时,若 \(k+1\) 位是偶数则 \(k'\leftarrow k+1\),并置为奇数,否则 \(k'\leftarrow 0\),将 \(k+1\) 置为偶数。
-
二次离线莫队
感觉没必要开单篇
其实就是一个拆贡献,差分算答案,并需要满足 \(O(n\sqrt n)\) 扫描线 \(O(1)\) 查询答案。
需要满足点对区间的贡献可差分,设 \(f(i,l,r)\) 为加入或删除 \(i\),当前指针为 \((l,r)\) 的贡献。需要有 \(f(i,l,r)=f(i,1,r)-f(i,1,l-1)\)。当然删除自然的有可能可以另设一个 \(g\)。
这样根据指针移动的时候拆出贡献,对于每个计算的 \(f(l,1,k)~f(r,1,k)\),在 \(k\) 处记录四元组 \((l,r,id,op)\) 表示对于 \(i\in [l,r]\),把 \(id\) 处的答案加上 \(op\times f(i,1,k)\)
这样的 \(O(\sum r-\sum l)=O(n\sqrt n)\)
需要提前预处理 \(f(i,1,i-1)\)
for(int i=1;i<=m;i++)q[i].l=read(),q[i].r=read(),q[i].id=i; sort(q+1,q+m+1); for(int i=1;i<=n;i++){ pre[i]=fid(a[i]);add(a[i]);//计算f(i,1,i-1) } memset(lz,0,sizeof lz);memset(f,0,sizeof f); for(int i=1,l=1,r=0;i<=m;i++){ if(l>q[i].l)v[r].emplace_back(q[i].l,l-1,i);//记录 while(l>q[i].l)--l,q[i].ans-=pre[l]; if(r<q[i].r)v[l-1].emplace_back(r+1,q[i].r,-i); while(r<q[i].r)++r,q[i].ans+=pre[r]; if(l<q[i].l)v[r].emplace_back(l,q[i].l-1,-i); while(l<q[i].l)q[i].ans+=pre[l],++l; if(r>q[i].r)v[l-1].emplace_back(q[i].r+1,r,i); while(r>q[i].r)q[i].ans-=pre[r],--r; } for(int i=1;i<=n;i++){ add(a[i]); for(auto [l,r,id]:v[i]){ for(int j=l;j<=r;++j){ if(id<0)q[-id].ans-=fid(a[j])-(j<=i);//这样要特判自己对自己的贡献 else q[id].ans+=fid(a[j])-(j<=i); } } } for(int i=1;i<=m;i++)q[i].ans+=q[i-1].ans;//我们实际求出的是一个差分数组,现在还原 for(int i=1;i<=m;i++)ans[q[i].id]=q[i].ans; -
P7906 倍增式值域分块,令 \(t=\log_2 V\),则将值域从 \(0\) 开始每 \(2^{\frac{t}{2}}\) 分一个块,则每次零散的值域修改时,至多修改 \(2^{\frac{t}{2}}\) 个块,且至多修改 \(2^{\frac{t}{2}+1}\) 个散点。且对于每个点开始其块头非常容易查询,
(x>>d)<<d即可,并且跳块也是相对容易的,在修改时,我们利用lowbit将修改拆为若干个 \([c,c+2^j-1]\) ,这样只需要保证块内值的第 \(j\) 位不变即可,若变立刻break。同样总时间复杂度还是 \(O(\log V+\sqrt V)\) 单次。相当优秀。 -
支配点对
用于对区间询问的处理,本质不同贡献(种类数,最优解等)。
简单来说,就是对于两个点对 \((a,b),(u,v)\) 而言,若 \(a\le u\le v\le b\),且 \((u,v)\) 的贡献”支配“了 \((a,b)\) 的贡献(贡献相同),则 \((a,b)\) 无论在什么时候都是无用的。而我们只需要寻找到一定数量的支配点对,则就可以更快的处理问题。本质是排除无效决策。常见的统计支配点对的方法有启发式合并,树分治等。
我们求出所有的支配点对之后,将询问离线,用数据结构维护答案,动态移动 \(r\) ,每次将 \(r\) 有关的支配点对 \((l,r)\) 加入贡献中即可。
例子:
-
给定一棵树,每次询问区间 \([l,r]\),求 \(\min_{i,j\in [l,r],i\neq j}dis(i,j)\)
用点分治,对于每个分治中心,求出当前连通块所有点到它的距离,则按照编号顺序依次加入点,维护一个 \(dis\) 的单调栈,满足编号递增的同时 \(dis\) 递增,每次加入新点的时候会与弹掉的点以及弹完后剩下的点构成支配点对。容易证明这样有 \(O(n\log n)\) 个支配点对且完全支配了所有询问。
-
给定一棵树,每次询问区间 \([l,r]\),求 \(dep_{lca_{u,v}},u,v\in [l,r]\) 的种类数
考虑到 \(lca\) 只有本质不同的 \(O(n)\) 种,所以我们对每个 \(LCA\) 都统计关于它的支配点对。
这是容易的,我们对于这个 \(LCA\) 的每颗子树里的每个点,与其他子树里的所有点,编号的前驱后继构成支配点对。
显然,我们用线段树合并,将线段树初始化为重儿子的线段树,然后对每个轻儿子,先统计其在线段树上有的前驱后继。然后再将其加入线段树中。根据启发式合并的结论,显然一共有 \(O(n\log n)\) 个支配点对
-
给定序列,每次询问一个区间内的数,两两最小差绝对值的最小值
序列支配点对一般满足以下构造:- \((l,l+1)\) 是必要的,令 \(now=l+1\),往后寻找。
- 若 \(k>now\),且 \((l,k)\) 为支配对,则 \((l,now),(now,k)\) 均无法支配 \((l,k)\)
- 若此性质可以极大程度减小 \(k\) 的范围,则可以尝试支配点对。一般有可能合法取值集合减半之类的。
- 不断令 \(now=k\) 即可。寻找过程最好用数据结构优化
如此题,我们先只考虑差为正的,差为负的翻转序列做一次即可。
\(l<now<k,a_l>a_{now},a_l>a_k\)
\(a_{l}-a_{now}>a_{l}-a_k\implies a_k>a_{now}\)
所以 \(|a_{now}-a_k|=a_k-a_{now}>a_l-a_k\implies a_k< \frac{a_{now}+a_l}{2}\)
值域减半
-
-
P6779 分块后对于每个块用线性结构维护当前可能的决策集合,并维护当前块内答案,保证每个块在没有散点修改的情况下,至多 \(O(n)\) 次操作决策集合便归一,这样整块直接暴力修改,总复杂度 \(O(n\sqrt n)\),同时散块修改时对决策集合总大小的影响不超过 \(O(n\sqrt n)\)(无用决策再次有用),可以暴力修改,并重新加入决策集合,时间复杂度均摊正确。同时我们甚至可以考虑树链剖分等结构中,每条重链的总贡献。
-
P7712 隐式建图 例如求割点的例子,我们考虑到 \(tarjan\) 算法中,真正只会进入 \(O(n)\) 次递归,而与 \(m\) 有关的开销仅仅在于 \(dfs\) 树上的返祖边,横向边之类的 \(low_u'\leftarrow \min(low_u,low_v)\) 这里是 \(O(m)\) 的。且真正与是否是割点有关的那些点都是未访问点造成的,这显然。
所以我们可以隐式的用数据结构建出边,但是只支持查询给定区间的一个未标记点,以及整个区间的 \(\min low\) 即可。
根直接特别处理,
find的时候pushup即可,平摊下来最多多走一次,对于选定的每个连通块。如本题中,面对两个维度的限制信息,我们用主席树优化建图,每颗主席树里存着这个点的所有出点,
insert的时候注意add,del。然后每棵树维护每个点的 \(low,dfn\) 值。这样可以主席树上二分找到未走的点,并直接顺带计算其dfn并递归。顺带维护 \(low\) 的信息。注意到一个特别的地方是,虽然主席树有很多版本,但是每个叶子只有至多三个版本,未出现-出现-未出现。这意味着我们进入一个新的连通块的时候,直接暴力修改连通块根的
dfn值顺带在主席树上其出现的点也改了,然后findnxt和findmn的时候顺带pushup即可。(在findnxt时,因为只改了叶子,所以会二分到这个根,这时候会意识到已经改了,就会回溯,并pushup,这样每个根只会多访问一次,不影响复杂度)。void dfs(int u,int fa){ if(!fa){ mn[apd[u]]=++num;cnt[apd[u]]=0; } dfn[u]=low[u]=num; for(int v=seg::find(rt[u],1,m,li[u],ri[u]);v;v=seg::find(rt[u],1,m,li[u],ri[u])){ dfs(v,u); col[u]+=(low[v]>=dfn[u]);low[u]=min(low[u],low[v]); } seg::trans(rt[u],1,m,li[u],ri[u],low[u]); if(!fa)col[u]=col[u]>1; else col[u]=col[u]>0; } -
CF1993E 经典问题特殊化
-
换视角看问题,有时候不妨给矩阵增加一行一列作为辅助信息
-
给定矩阵,可以进行任意次操作,每次可以选择两列或者两行整体交换,求最终相邻方格中的数的绝对值之差的和的最小值
矩阵问题,可以行列拆贡献,容易发现交换列不会影响行之间的答案。
所以 \(f_{i,j}\) 为\(i,j\) 两行最终相邻的值,\(g_{i,j}\) 为列。这是一个特殊的TSP问题。
-
-
CF1993F 类似糖果云:往左走,走到边界后变向往右走,然后走到边界又弹回去。可以考虑无视回弹,将平面折过去,变成 \(\bmod 2len\) 实时位置。二维也是一样的。斜线也是一样的,都考虑 划曲为直。
-
ARC181C 构造方案同样可以考虑找极端/特殊位置优先决定,然后划分同类问题。也就是运用分治思想
-
给定无向连通图,构造生成树 \(T\) 满足对于原图任意一条边 \((u,v)\),树上两点路径中所经点的最大最小值分别是 \((u,v)\)
则贪心构造:钦定 \(u<v\) ,按照 \(v\) 升序,如果 \(v\) 相同按照 \(u\) 降序排序,做类Kruskal
如果存在 \(T\),这样一棵树一定合法。
同样的,也可以按照 \(u\) 降序,相同时按照 \(v\) 升序,做类 Kruskal
两棵树相同则合法
本题是这样的一个类问题:对于每条边删除后是否存在。类次小生成树处理即可
-
CF1458C 如果涉及到逆排列的转化 \(Q_{p_i}=i\) ,其实是维护若干二元组 \((i,p_i)\) ,一次转化就是交换两个元素。
-
P2152 点化边更灵活的处理行走问题。去重——枚举最后一条行走的边。
-
NOIP模拟1T3 给定若干区间 \([l_i,r_i]\),若去掉包含后,按照 \(l\) 排序后 \(r\) 同样是单调的。
-
以下以递增单调栈为例
线段树每个位置维护最大值 \(mx\) 和这个区间做单调栈后的元素个数 \(len\) ,定义 \(calc(t,x)\) 为只使用 \(>t\) 的元素做单调栈后的大小。
\(len_x=len_{lc}+calc(mx_{lc},rc)\)
\(calc(t,x)\) 计算
- 单点直接判
- 若 \(mx_{lc}>t\),则 \(calc(t,x)=calc(t,lc)+len_x-len_{lc}\)
- 否则 \(calc(t,x)=calc(t,rc)\)
复杂度 \(O(n\log^2 n)\)
-
将 \(1\sim n\) 按顺序加入双端队列,则得到的序列是首项到 \(1\) 递减,然后 \(1\) 到末项递增。
-
将 \(1\sim n\) 按顺序加入双端队列,然后按任意顺序取出的一个排列 \(p\) 必然满足在 \(1\) 之前的数可以拆分为两个递降序列。而后面的可以任意操作。
-
序列 \(a\),要求进行若干次操作,每次将所有值为 \(x\) 的数改为 \(y\),最终需要满足 \(\forall a'_l=a'_r,a'_l=a'_{l+1}=a'_{l+2}=…=a'_r\),代价是两个序列不同位置个数。支持单点修改,答案查询。
显然需要进行划分段,使得每一段的值 “封闭”,然后每一段保留众数。
这个划分可以考虑对于每个值,设第一次在 \(s\) 出现,最后在 \(t\) 出现,对 \([s,t)\) 进行 \(+1\) 标记,最后值为 \(0\) 的位置就是每个段的划分点。半开半闭区间做标记,标记零点划分,这个转化非常妙,将线段交转化为了 \(+1\) 判 \(0\)。且答案就是 \(n\) 减去每个"连续段"的最大值的和
我们在线段树上维护最左最右两个“连续段”的值的最大值,整个区间的最大值 \(lx,rx,mx\),并且维护除掉最左最右的答案和,以及这个标记值。将每个”值“ 的权值放在第一次出现的位置上,维护整段区间标记后的最小值 \(mn\),这个在修改的时候(当作删除和增加)相当于区间修改 \(mn\)。注意 \(lx,rx,mx\) 是对每个值的出现次数的维护,而 \(mn\) 就是单纯的是否连续的标记
这样我们就可以根据 \(mn_{lc},mn_{rc}\) 的大小关系进行求解了。(两者相同直接合并,两者不同则较大的那个一定是一整段都是连续的)
注意单点时我们只记录 \(lx,mx\) 防止重复。
-
-
一个平面上的整点,有若干黑点,其余都是白点,则黑点组成一个矩形(填满)的充要条件是:
有且仅有 \(1\) 个黑点其左侧,上方是白点(这个所有情况下都最少有一个)
没有白点其四联通的点至少有两个黑点
而我们只用维护这两类点的总和,判断是否为 \(1\) 即可。这样甚至可以做到动态增删。
-
命题的转化:
给定一个 \(n\times m\) 的矩阵,元素是一个 \(n\times m\) 的排列,求有多少子矩阵满足 \(1\sim area\) 全部在里面。
这个问题等价于,每个元素的坐标 \((x_i,y_i)\),求有多少个 \(i\) 满足 \((\max_{[1,i]} y-\min_{[1,i]}y+1)(\max_{[1,i]}x-\min_{[1,i]}x+1)=i\)
这个问题同样等价于,最初全为白点,逐步将 \(1\sim n\times m\) 变为黑点,并且动态计算。
同时第三个命题还可以支持交换两个点的值。具体地,可以将每个点作为第一类黑点和第二类白点的“时间段”处理出来,这是连续的(第一类就是 \([a_{x,y},\min(a_{x-1,y},a_{x,y-1})-1]\),第二类就是四联通里次小值 \(cmn\),\([cmn,a_{x,y}-1]\))。
而交换位置,等价于重置两个位置及其四联通总共 \(10\) 个点的权值(注意不能重复操作一个点)
-
-
CF283E 对于一个不合法的有向三元环(也就是 \(i\to j\to k\leftarrow i\)),有且仅有一个点出度为 \(2\),有且仅有一个点出度为 \(1\)
Expand:给定 \(01\) 矩阵,若 \(a_{i,j}=1\) 表示存在有向边 \(i\to j\),否则是 \(j\to i\),有 \(a_{i,i}=0\) 则三元环个数为 \({n\choose 3}-\sum {cnt_i\choose 2}\),其中 \(cnt_i\) 是第 \(i\) 行 \(1\) 的个数。
-
CF407E 一个序列 \(a\) 若加入 \(k\) 个数后可以形成公差为 \(d\) 的等差数列(\(d\neq 0\)),充要条件
- 所有数 \(\bmod d\) 相同
- 不存在相同的数
- \(\max-\min\le (len+k-1)·d\)
-
经典问题:给定 \(N\) 个点每个点有颜色,以每个点为左上顶点做 \(d\times d\) 的正方形,判断是否存在一个点被每一种颜色的正方形都覆盖到过
去重颜色相当经典,扫描线 \(x\) 的同时维护每个颜色此时出现的 \(y\) 的集合
multiset插入一个点的时候查其前驱后继求得新覆盖区间(必然是区间),删除一个点时查前驱后继得到唯一覆盖区间。 -
势能线段树
几个注意点:
- 对于单调函数 \(f(x)\),记录 \(\min,\max\) 的函数值,相同就转化为覆盖/加减等操作。如区间除法可以维护函数 \(f(x,k)=x-\lfloor\frac{x}{k}\rfloor\),若 \(f(\max,k)=f(\min,k)\) 就转化为区间修改,又因为最多 $\log $ 次 \(|x|\le 1\),保证复杂度。
- 关注种类数,递变量
- 取模,开根,有效的操作都至少使得原数减半
-
吉司机线段树,例题 link
- 维护区间取 \(\min/\max\),区间求和,以取 \(\min\) 为例。
维护 \(mx,cmx,cnt_{mx}\)。
修改时,若整段 \(mx\le k\),返回
若 \(cmx\ge k\),暴力递归修改
否则只有 \(mx\) 变为 \(k\),据此维护信息即可。
- 维护函数 \(f(x)=\max(x+a,b)\),当然 \(\max\) 也行。这是分段函数
取 \(\max\) 时,\(a'=\max(a_0,a_1),b'=\max(b_0,b_1)\)
合并时,\(a’=\max(a_0,a_1),b'=\max(b_0+a_1,b_1)\)
可以用线段树维护
- 维护历史信息
- 历史最值:记录历史最优答案,记录历史最优懒标记。
- 历史和:多记录一个 \(t\) 表示当前尚未更新的版本数。
父亲传下来的懒标记在儿子的懒标记之后发生,注意顺序。
-
对于类范德蒙德卷积,但是有上下界的限制,此类式子属于 不可得封闭形式,往往采用容斥,递推等方法求算具体范围的值。
例 \(\sum_{i=0}^k\sum_{j=1}^n{{s_j\choose i}}{n-s_j\choose m-i}\)
由于有上下界不可计算,但是可以设 \(f_s=\sum_{i=0}^k{s\choose i}{n-s\choose m-i}\),这样枚举每个 \(s_j\) 即可计算答案。
根据组合意义,其实相当于 \(f_0={n\choose m}\),而 \(f_{s}\) 之间,相当于是在 \(n\) 个球里选 \(m\) 个且要求前 \(s\) 个位置最多选 \(k\) 个位置。
\(f_s\to f_{s+1}\),仅仅是多算了 恰巧选了第 \(s+1\) 个位置,且它是第 \(k+1\) 个球的方案数,所以 \(f_{s+1}=f_s-{s\choose k}{n-s-1\choose m-k-1}\)
-
关于数值较小(四五十或者更小)的连通性问题,可以 状压连通情况。也即状压当前大小为 \(i\) 的数组有多少个,或者是状压当前各个连通块大小(排序)。状态仅仅有分拆数个
-
全局加一 在 \(01trie\) 上体现:
我们将所有数按低位开始插入01trie,每次全局加一,相当于将二进制末尾的所有 \(1\) 改为 \(0\),然后下一个位置变成 \(1\)。
在 \(trie\) 上体现为交换当前节点的左右儿子,然后进入 新的左子树 继续交换即可。
低位 \(01-trie\) 很方便的支持全局加一,单点修改的操作,但是却做不了 \(max/min-xor\),不过可以维护全局 \(xor\) 和。(从低到高维护,本质上是一种分治结构)
-
SDOI2011 植物大战僵尸 还是坐标变换的问题
众所周知,遇到 \(45^{\circ}\) 直线,往往进行 \((x,y)\to (x+y,x-y)\) 化斜为直
众所周知,遇到边界反向,往往进行扩域,将地图复制一倍,然后坐标对两倍原边界取模。
当两者相结合,也可以进行如此操作,但需要注意坐标从 \((0,0)\) 开始。这样可以方便的将遇到边界反弹,遇到人反弹的链建立出来。
-
\(FWT(1)=[1,1,1,1,1,……]\)
\(FWT(1+x^a)\) 仅有 \(0,2\),且取 \(2\) 的位置 \(k\) 满足 \(popcount(k\&a)\bmod 2=0\)
广义 \(FWT\),第一维 \(xor\) 卷积,第二维乘法卷积。
\[FWT_{ex}(F(x,y))=\sum z^j\sum_{i}(-1)^{d(i\& j)}f_{i,k}y^k \] -
利用最值的最优化,简化一些情况
遇到类似于带绝对值的不等式,可以拆掉绝对值对各种情况求最值。
遇到求解满足一堆最值限制的点对,可以考虑枚举其中之一,然后利用单调性维护各个限制的合法区间最后取交集
例如本题求:
\(\forall i<j,d_i+d_j+s_j-s_i>mid\),判断是否存在 \(l<r\),满足 \(d_i+d_j+|s_i-s_l|+|s_r-s_j|<k\)
可以考虑拆解绝对值,变为
\[\begin{cases} d_i+d_j+s_i+s_j-k<s_l+s_r\\ d_i+d_j-s_i+s_j-k<-s_l+s_r\\ d_i+d_j+s_i-s_j-k<s_l-s_r\\ d_i+d_j-s_i-s_j-k<-s_l-s_r\\ \end{cases} \]对所有点对按照 \(d_i+s_i,d_i-s_i\) 各排一遍序,然后枚举 \(d_i-s_i\) 这样另一个单调,可以处理出上面四个不等式左式的最大值 \(A,B,C,D\),枚举 \(r\),根据四个条件,此时 \(l\) 对于每个值来说是单调的,维护四个指针找 \(l\) 的合法区间,最后看区间是否交集不为空即可
-
树的重心 CSPS2019 树的重心一定在当前根节点所在重链上。可以假设法证明。
-
\(\min(a,b)=a+b-\max(a,b)\),这是 \(\min-\max\) 容斥最简单形式。
\(\min(a,b)=\sum_x[x\ge a\& x\ge b]\)
-
CF2001E2 在对于二叉树,二叉堆等结构进行计数时,综合应用对称性可以极大程度简化问题。等效性,对称性
-
HDU6566 独立集与点分治的结合
点分治核心结论:点分树上两点 \(LCA\) 在原树两点路径上。推论是原树上相邻两点在点分树上为祖孙关系。
点分树高严格小于等于 \(\log n +1\)。
所以一个类似于依赖背包的问题,涉及到独立集,可以状压点分树祖先的情况,就可以处理相邻关系了。 -
找带权重心:考虑点分治优化查询:依据:往一个方向移动一步一定更优。所以可以利用点分树结构,每次枚举点 \(u\) 在原树的相邻节点,找哪个移动后代价减小,接着找到方向之后去相应方向的点分树节点。
-
CF364E 二维分治模版题 统计子矩阵的贡献,可以考虑进行分治,找到一条整体的划分线,将矩阵切为两半,维护到分割线的信息,类似于卷积合并两半的信息。一般采用哪一维更长则分治哪一维 复杂度 \(O(nm(\log n+\log m)t)\) 其中 \(t\) 是一个附带复杂度。每一层可以遍历每个点。
-
BZOJ2961 判断所有点是否都在某直线上/下方,将点求出上(判直线下方)/下凸壳,可以考虑做该直线的平行线与凸壳相切,这样的切点可以在凸壳里找到,判断这个点与原直线的关系即可。
-
P3206 动态改边权,动态求解MST 涉及核心思想 尽可能使得分治复杂度只与 \(len\) 有关 首先线段树合并只有加边
考虑将所有可能的边权值设为 \(0\) 也就是提前合并后,若还有边可以在本层合并连通块(也就是做Kruskal,记得排序)则为必选边,算上权值。剩余边有几种情况
- 不算尚未加入的所有可能边以及本层拿出的必须边,只用本层边做Kruskal被选中,说明仍有被选中的可能,下传
- 否则无效,删除
我们每次可以保证至多下传 \(O(len )\) 条边。(其实可以看作是分治求解MST,一层层筛出必用边)
-
只在乎二进制前 \(k\) 位前缀,可以建立一颗满Trie并记录每个前缀所对应的节点可以做到 \(O(1)\) 插入,\(O(\log n)\) 查询所有前缀的和。
-
CF2003F 从一个带颜色的序列中取出一个长为 \(m\) 的子序列要求颜色不重复,且满足其他限制,但是颜色个数太多无法状压,可以考虑将所有颜色映射到 \(m\) 种,那么取不到答案的概率是 \(\frac{m!}{m^m}\)。核心思想是建立大集合到小集合的哈希映射,通过概率分析和重复操作取得最优解。
-
CF2003E2 考虑逆序对数的求算,可以将 \(\le x\) 的变成 \(0\),大于 \(x\) 的变成 \(1\),这样只需要计算 \(10\) 对的个数以及 \(0\) 之间以及 \(1\) 之间的逆序对数。
-
一个 \([1,k]\) 的正整数序列要求重排后相邻两项的积不超过 \(k\),必然是按照最大最小次大次小来排列的
其合法的充要条件可以表述为:
- 排名为 \(i\) 的和排名为 \(n-i+1\) 的数的积的最大值不超过 \(k\)。
- \(\forall i\le \sqrt n,cnt[1,i]\ge cnt[\lfloor\frac{k}{i}\rfloor,k]\implies cnt[1,i]+cnt[1,\lfloor\frac{k}{i}\rfloor-1]\ge cnt[1,k]\)
-
WD与地图 二分每条边两个端点位于同一个 SCC 的时间。
-
路在何方 类似于 \(dp_i=\min_j(\max(w_{i\to j}),dp_j+c_{i\to j})\) 类的动态规划都可以利用最短路建模优化。
-
Od deski do deski \(dp\) 状态设计可以设计被禁止位置个数。
-
有趣的家庭菜园 3 每次交换相邻两个数达到目标状态的最小操作次数。将原序列映射为 \(p_i=i\) 的排列,然后可以类似于填数(原本是 \(i\) 的位置现在是 \(j\))之类,通过记录信息来构造最小逆序对数进而求解答案。
-
JOISC 2015 Day 2 Keys 图论与动态规划结合
- 按时间顺序依次考虑事件的影响
- 发现可以建立图论模型,类似于选点 \(i\) 有贡献 \(v\) ,同时选 \(i,j\) 有贡献 \(w\),可以建立图论模型(如果只有点权还有一个最大权闭合子图)
- 对于特殊类型的图(例如树,链,DAG)可以用DP处理。(也可以考虑缩点变为特殊结构)
-
双栈维护首尾刪插整体查询问题。
使用一个栈维护头插/刪,一个栈维护尾插/刪。
当一个栈需要刪却空时,先将另一个栈切为两半重构(暴力,注意顺序),根据势能分析重构总量是线性的。
注意特判总的只有一个元素的情况。
查询合并栈顶信息。
-
四方向移动:\((x,y)\to (x+d,y)/(x,y+d)/(x-d,y)/(x,y-d)\) 在转切比雪夫距离后等价于两个维度同时操作 \(\pm d\) 。
则可以达到 分离两个维度的目的。
-
给定一颗树,请给树边改成有向边,求连通的点对个数的最大最小值。点对连通,要么 \(a\) 能到达 \(b\),要么 \(b\) 能到达 \(a\)。
以一个点为根时,必然一部分子树内的边全部向上,另一部分全部向下,且向下和向上各自的边数尽可能接近。
-
QOJ6355 注意到若状态为 长为 \(k\) 的和为 \(T\),则考虑将 \((k,T)\to (T-k,T)\) 显然变换是双射,且此时具备性质:
则对于一个 \(T-k\) 而言其 \(T\) 必然是若干段连续的区间, \(1\) 若足够多,则区间必然很少。考虑 \(1\) 不影响 \(T-k\) 的存在,则删除 \(1\) 后的 \(T\) 是区间 \([l_1,r_1]\sim [l_m,r_m]\) ,设有 \(x\) 个 \(1\),则加入 \(1\) 后是 \(\cup [l_i,r_i+x]\)
至多有 \(\lfloor\frac{S}{x}\rfloor\) 段。
-
枚举树上叶子计算依赖性背包的答案。需要特别计算叶子到根的链,可以考虑正序遍历儿子做一遍 \(dfs\) ,再倒序遍历一边做 \(dfs\),合并两次计算的结果(注意不要算重)
划分断点,拼接思想
-
ZJOI2012 波浪 计算长度为 \(n\),\(\forall m\in [1,n^2],\sum_{i=1}^{n-1}|p_{i+1}-p_i|=m\) 的排列 \(p\) 个数 。
填数考虑连续段 dp 是显然的。
然而这个计算方式值得学习:
从大到小填入数字,将其想象为长为 \(n\) 的一排盒子里面依次填入编号为 \(1\),\(2\dots\) 的球,则这个相邻项差的绝对值之和相当于相邻两个球放入时间的绝对值之和。那么就可以按照连续段 dp 的思想:目前放入的球构成的 \(j\) 个连续段,则这 \(j\) 个段的左端点的左边,右端点的右边放球的代价可以提前计算,这一时刻就给答案加上 \(2j-p-q\),\(p\),\(q\) 为第一个盒子和最后一个盒子放没放
-
P3188 二进制分类优化超大容量01背包
-
AGC020E 及时划分子问题意识,设计两个 \(dp\) 处理合法串拼接/压缩方案数问题:钦定最后一个带括号/特殊的段位置
-
- 如果一个涉及值域变换的问题,01序列版本都做不出来,那么原序列问题肯定无法解决
- 原问题经过二分将 \(\ge x\) 的数字置为 \(1\) 之后的问题严格弱于原问题,且往往具有优异的扩展性。
- 最大值贡献统计,往往可以考虑以下方向:钦定最大值,二分最大值计算差量,计算相对关系。
-
经典 trick:关于 min/max 的非 ds 问题先想 01 序列上面怎么做(你不会 01 序列一定不会原问题)
-
- 处理区间限制与序列DP之间的关系,可以考虑当前点收到的最强的限制进行转移。
-
对于环上的均匀 \(2n\) 个点,将其两两配对,定义两个点联通当且仅当两点在同一条线段上或者两点所在线段相交,则若将配对的两个点 \(i<j\) \(i\) 看作左括号,\(j\) 看作右括号,则有连通块个数与非嵌套最大匹配括号序列个数,
等价转化命题也有 \([l_1,r_1]\) 与 \([l_2,r_2]\) 相交但是不包含则在圆上相交。
也就是每一个连通块 必然对应一个区间,若用 \([L,R]\) 来表示,则所有连通块对应区间要么包含要么不交。
看成括号序列也就是一个匹配的括号序列对应一个大的连通块,而其内部拼接方案对应小连通块
-
按下标顺序插入 \(BST\),本质上是 \((i,p_i)\) 的第二维 \(BST\),第一维小根堆,也就是若交换成 \((p_i,i)\),也就是建立 \(p_i\) 的笛卡尔树。
-
-
对于 \(01\) 序列的 \(LIS\) 可以写作 \(\max_i(i-s_i+s_n-s_i)=\max_i(cnt_{0,i}+cnt_{1,n}-cnt_{1,i})=s_n+\max_i i-2s_i\),令 \(p_i=cnt_{0,i}-cnt_{1,i}=i-2s_i\) 则问题等价于转化为维护 \(\max p_i\)
-
对于恰好 \(k\) 次选择一个区间进行翻转,能且仅能可以让原本序列中 \(k+1\) 段互不相交的区间成为一个整体区间。
-
对于取出权值和最大的 \(k\) 个区间,可以 \(1\to k\) 按次操作取出当前的最大子段和,然后将这一段变成相反数。
证明:首先取当前的最大子段和相当于如果包含了之前选的一个整段,相当于扔掉这个整段,如果相交相当于删掉相交部分,如果不包含显然成立。
并且显然不会出现两个之前被选择的段同时被包含的情况出现,这样的话这个子段早被选了。
-
-
在 \(dp\) 设计时,若独立变量并不容易转移,可以考虑设至多至少,但是一定要注意去重。当然这一般涉及了最值的计算。
-
注意到对于质数 \(p\) 而言有:
\({p\choose x}=[x=0\or x=p]\bmod p\)
所以在 \(p\) 较小时,求算在限制条件下的 \((0,0)\to (xp,yp)\) 的方案数时,可以考虑按斜线DP,也即只维护 \(dp_{x,y},p|(x+y)\)。
那么在转移的时候,按照 \(\frac{x+y}{p}\) 进行转移,每次 \((x,y)\) 只会对 \((x+p,y),(x,y+p)\) 产生贡献,其余全部是零。
如果有其它限制再进行容斥即可。
-
经典实数求算概率的样例。
-
对于 \(n\) 个随机变量 \(x_i\) 在 \([0,1)\) 之间随机,要求 \(\sum x_i\le k\) 的概率。
这里我们唯一有的条件是 \(x_i\le p\) 的概率是 \(p\)。
看作 \((x_1,x_2…x_n)\),我们考虑容斥,钦定 \(i\) 个元素大于等于 \(1\),则相当于求算剩下的元素任意且和至多为 \(k-i\) 的方案数。
直接求前缀和,则有 \(s_i\in [0,k-i]\),那么就有 \(\frac{(-1)^i{n\choose i}(k-i)^n}{n!}\),根据实数特性,不需要在意前缀和值相同的情况,这样的概率是 \(0\)
-
对于变量 \(x_i\) 设其上界是 \(m\),则 \(P(x_i\ge \sum_{j\neq i}x_j)\implies P(m\ge \sum _{j\neq i}x_j+m-x_i)\implies P(m\ge \sum_{j} x_j)\)
这个转化相当妙啊,因为 \(x_i\) 与 \(m-x_i\) 完全对称。
-
-
先进行所有 \(and\) 操作一定最优。
-
无向图中若一个点只有当与它直接相连的点中最多只有一个点未被选择过时才可被选择,求选点方案数,则若一个点在环中则必然不可选,删去后剩下若干树,若一个合法点与某个环点直接相连,则显然这个点是这棵树的根,且有这个选点顺序就是某种拓扑序。而若是无根树,则 枚举根,钦定这是没被删除的点里编号最小的,那么直接在以他为根的方案中将编号小于它的点全部删去且钦定自己不删
-
对于数 \(S\),若 \(\forall i,a_i|S\leftrightarrow lcm(a)|S\)。(cf55d)
-
状态压缩动态规划与最短路问题,等权边。
一般考虑采用三进制状压,\(0\) 表示未连通,\(1\) 表示是连通块里 \(dis\) 最大的点,\(2\) 是连通块内其他点,我们都是通过枚举 \(1\) 点的扩展遍集去扩展 \(0\) 点,涉及枚举子集操作。这里每个扩展点独立。
-
对于 \(\le N\) 的可以表示为 \(\prod p_i^{c_i}\) 的数字至多有 \(\prod \log_{p_i}N\) 个。往往在 \(p\) 个数很少的时候有大用。例如 \(p\in\lbrace 2,3,5,7\rbrace\) 时。
-
\(Boruvka\) 算法在求 特殊图/完全图 的时候相当有用。
考虑边权矩阵,我们只需要支持求出 每个点与其不在同一个连通块内的点的最小边权以及对应点,设这个操作复杂度是 \(O(t)\),则求解复杂度是 \(O(tn\log n)\),因为该算法至多执行 \(O(\log n)\) 轮。
将在同一个连通块看作是拥有同一种颜色,可以在每一轮循环的时候现场更新数据结构,利用数据结构查找。
可以利用线段树,平衡树等方向优化。
eg.CF888G,天空障
-
Slope Trick 指的是通过使用堆来维护函数拐点的技巧,其解决的转移主要是形如与某个固定的数作闵可夫斯基和,相比于平衡树,其优点有很多:方便对两个函数求和,常数小,好写等。但是往往不太方便进行两个凸包的闵可夫斯基和。
-
长链剖分的重要性质是一个点往上跳链顶至多有 \(O(\sqrt n)\) 个链顶。
-
注意到 \(\max(a,b)=\frac{|a-b|+a+b}{2}\),可以提出 \(a+b\),首尾用哨兵。
-
对于凸性相同的两个凸函数 \(f,g\),\(h=f+g\) 仍然是凸函数。
称一个数组是凸的当且仅当它的差分数组是单调的(不严格,直线也是一样的)
那么合并两个凸数组相当于首项相加,然后将差分数组归并。
一般的可以使用可并堆维护差分数组(首项单独维护) 达到快速合并多个凸数组的效果,一般是左偏树。注意将一个DP式如果困难可以尝试拆分为若干个凸性相同的函数和
当然也可以直接利用可并堆维护点的 \(x\) 坐标以及斜率的变化量,也就是 \((px,dk)\) 表示在 \(x=px\) 时,斜率增加了 \(dk\),在处理某些DP时会非常好用(\((\max,+)\) 卷积是闵可夫斯基和,而一些前缀/后缀形式的却没有这么好的状态只能如此维护(好处是 \(x\) 不会变化,所以维护 \((px,dk)\))。)。
一般而言都是画出图像,然后考虑转移式的影响,进而决定维护的信息
(转移式的影响可以拆解)
总之,维护 \(k\),还是 \((x,\Delta k)\) 根据情况选择。
-
在处理最优化子矩阵问题,复杂度在 \(O(n^2)\sim O(n^3\log n)\) 这一类时,往往考虑枚举上下边界进行处理。
与此同时,往往你从下往上枚举上边界,从上往下枚举下边界就只有加入而无删除。
同样的,也有思路是枚举下边界,然后维护一个 \(dp_{l,r}\) 表示 \(l,r\) 列之间,合法最优上边界。
-
打怪兽模型
设有 \(n\) 个怪,你有初始能量 \(v\),打怪 \(i\) 的前提是有 \(a_i\) 的能量,并且怪会消耗掉你 \(a_i\) 的能量,杀死怪后会增加 \(b_i\) 的能量,求最多打死怪个数。
假设我们知道一个集合 \(S\) 的怪存在一种策略被全部打死,则采用:
- 优先按照 \(a\) 的从小到大打 \(a\le b\) 的怪。
- 然后按照 \(b\) 从大到小打 \(a>b\) 的怪。
首先 \(a\le b\) 的策略显然正确,对于第二个策略,我们考虑打到怪 \(i\) 前还有能量 \(v\),打完怪 \(i+1\) 后还有能量 \(v'\),显然我们交换 \(i,i+1\) 是不会对 \(v'\) 产生影响的,但是先打血少的怪,可能会导致能量减少打不了血多的怪,反之没有这个问题,所以这样一定可行。
-
等效链,也就是将原本的图通过种种算法等效为一条链,然后利用数据结构维护答案。
这一步往往通过图的二叉重构树进行实现,只需要按顺序遍历一边叶子即可,且正确性可以放在重构树上思考。
-
CF2020E 涉及期望的平方与二进制运算操作,那么可以 \(E(x^2)=\sum P(x)x^2\) 可以对于两个二进制位 \(i,j\),没有大小关系,求两者同时为 \(1\) 的概率进行求算答案,当然多次方也可以如下处理,假设 \(k\) 次方可以做到 \(O(n2^k\log^k n)\) 的复杂度。
-
CF2020F 涉及变换为因子,求算函数值,考虑函数值是否是积性函数
-
求函数的前缀和,要么考虑 积性函数,要么考虑直接推式子
-
CF2018F1~3 Solution 优化重复DP技巧好题
-
CF2018E2 Solution 并查集维护后缀最大值,后缀加的相关信息,不改变相交关系的重标号区间端点使每个值唯一
-
当 边权 是出点的 点权 时,对于最短路算法而言,一个点在dijkstra算法中只会被其入点里第一个从堆中取出的点松弛一次,这启发我们直接维护点的存在性,支持快速查找一个点的后继,找完就删掉,这样的隐式建图可以避免各种各样奇怪的优化建图,只保留有用的边。
-
当只对虚树进行一遍自底向上的 DP 时,不需要显式建出虚树后 dfs,而是在构建虚树的过程中直接转移,因为构建虚树时每条边被加入的顺序就是回溯顺序。这样可以有效减小常数。
-
若干个点形成的虚树的路径最值就是这些点在 kruskal 重构树上的 LCA 的权值。
-
考虑对每个质因子单独算贡献。把与该质因子相关的节点和询问节点全部拉下来建虚树
-
经典DP:\(f_i=\min(w_i,\min_{i\to j} f_j+w(i,j))\),在不明确转移顺序且是正权图的情况下, \(w_i\) 最小的必然可以直接确定,将所有点的 \(w\) 扔进小根堆,每次取出堆顶进行更新,当一个 \(i\) 的所有 \(j\) 都已经拿出后再将 \(f_i\) 扔进小根堆更新。如果始终无法拿出 \(f\),或者是在 \(w\) 拿出后拿出 \(f\),说明这玩意取 \(w\)。
-
选一个节点能覆盖它到根的所有节点。选 \(k\) 个节点,覆盖的最多节点数就是前 \(k\) 条长链长度之和,选择的节点即 \(k\) 条长链末端
-
一个点集的 LCA 是其中 \(dfn\) 最大最小两个点的 \(lca\)。
一个点 \(x\) 到一个点集 \(S\) 的路径,可以看作对 \(S\cup\lbrace x\rbrace\) 建立虚树,以 \(x\) 为根。
一个点集 \(S\) 内部两两之间简单路径所经过的边权的最大值是Kruskal重构树上点集 \(S\) 的LCA的点权。
树上点 \(x\) 到点集 \(S\) 的所有边集是 \(S\cup \lbrace x\rbrace\) 组成的虚树所构成的边集。 -
点分治线性合并子树时,合并代价是 \(O(siz_{v_1}+siz_{v_2})\),新子树总量是 \(\max(siz_{v_1},siz_{v_2})\) 时,可以按照 \(siz\) 从小到大合并,这样就是线性的。
-
最小生成树的求法:Kruskal,Prim,Boruvka,下面是各个算法在解决奇奇怪怪最小生成树的时候的应用场景。
- 其中 Kruskal 要求边数 \(m\) 较小,往往我们与支配点对相结合。
- Prim 一般要求完全图,往往复杂度炸掉
- Boruvka 往往用于,将点进行染色之后,可以快速求出与其颜色不同的节点的最小边权。这样就可以合并到一个连通块往外的最小边权了。运用时,我们往往维护两个最优的不同颜色进行处理(最优与颜色不同的次优,这个思想在染色找不同色的时候往往很有用)。
最小生成树的重要性质是:任意选出一个边集 \(E\) 对其求最小生成树森林,若一条边没有被选中则不可能成为最小生成树边。
借此可以得到一个求支配点对的方法:只需要保证求的过程中我们每一步考虑的边集的并是全集即可。
给定树,求完全图最小生成树,边 \((u,v)\) 的代价 \(val(u,v)=w_u+w_v+dis(u,v)\),树有边权,则点分治,找到区域内 \(w_x+dis(x,rt)\) 最小的点,则对这个局部分量求最小生成树的结果就是以 \(x\) 为中心的菊花。
-
对于区间 \([l,r]\) 的笛卡尔树,求出最大值位置 \(p\),则 \([p,r]\) 的笛卡尔树就相当于是 \([1,r]\) 的笛卡尔树里 \(p\) 的右子树,反之同理,询问的时候可以根据 \(p\) 将区间割为两半,使用单调栈建树的过程本质上相当于保留一条向右的链,弹栈的时候相当于是平移位置,插入点相当于是把原本的一颗子树往左下平移,然后加入新点,连上去。
对于和最值有关的题目,将询问按照区间最大值分割成两个互不相关的查询可以有效简化问题。同时,左右两端第一个大于 / 小于当前值的位置有很好的性质。
-
枚举每个
bit位,将一个集合按照该位的值 \(0/1\) 分组,可以在额外增加 \(O(\log V)\) 倍的时间复杂度内统计一整个集合两两之间的答案,要求可以快速计算两个集合之间的答案。 -
正反图跑dijkstra并染色,所要求的最短路必然不会经过第三个特殊点,且两个特殊点之间的路径存在一个中边,枚举它,左右端点的最优解不同,直接算进答案,显然不会少算,也不会算到更优的非法解。
-
建立 \(k\) 正则二分图,随意拿出一组完美匹配不会影响局面,只会变为 \(k-1\) 正则二分图,且一个正则二分图一定可以有完美匹配。
- vizing 定理的另一个简化形式是,我们最少可以用 \(k\) 种颜色给k正则二分图染色,使得每个点的出边颜色不同。
-
对于无向连通图上的 \(n\) 个点任意划分为若干个集合,不同集合两两之间最小边的最小值一定在 \(MST\) 上,这是由连通性决定的,无论是 Kruskal,Prim,Boruvka 都是基于这个思想。
-
类比点分树的计算方法,如果是修改点权,但是影响的是边的贡献,那么我们每个点维护到儿子的所有边的贡献,这样可以将点权影响的边变为只需要整体改动(修改点的儿子)和单点修改(修改点的父亲)。
-
事实上
Trie处理按位与往往将“1”子树与“0”子树合并在一起作为新的零子树,按位或同理(像线段树合并一样)每个点最多合并 \(\log V\) 次。 -
\(LCS(S,rev(S))=LPS(S)\),也就是最长回文子序列长度。
-
一个
R,B两个元素构成的序列,其能够拿出的最多RB子序列数量是看作 \(1,-1\) 的折线图后去掉起点到最低点到终点部分的元素之后所有的元素都会有贡献。 -
将树染为黑白色,则全树中同色点两两之间距离最大值的方案的某个端点必然是直径端点。
-
对于一张二分图而言,设有两个不同的最大匹配 \(M_1,M_2\),且 \(M_1\) 的匹配左部是 \(L\),\(M_2\) 的匹配右部是 \(R\),则必然存在最大匹配 \(L\cup R\)
-
给定二分图 \((A,B,E)\),其中 \(A,B\) 是两部点集,\(E\) 是边集。对于 \(B\) 中的每个点都给定一个点权。定义该二分图上的一个匹配的代价为所有 \(B\) 中的匹配点的点权之和。求在匹配最大的情况下,匹配代价最小可能是多少。做法:将 \(B\) 中的点按点权从小到大排序,并以这个顺序跑匈牙利算法(按序依次增广),最后跑出来的匹配就是代价最小的最大匹配 \(M\)
-
PKUSC2019 树染色。
通过线段树合并的整体性质与优秀复杂度进行优化DP,对于相同的状态可以用线段树上节点维护 \([l,r]\) 如果没有儿子说明整段状态相同,整体转移。
-
arc092F 翻转边 \((u,v)\) 对强连通分量个数产生影响,当且仅当以下条件满足且仅满足一个
- 原图中存在一条 \(v\to u\) 的路径
- 原图中存在一条不包含 \((u,v)\) 的 \(u\to v\) 的路径。
-
对于有黑白两色边的情况,对于一个点双连通分量而言,如果边全白或全黑,说明两两路径只能说全白或全黑,否则,除非白边和黑边将原 VDCC 分为两个部分,两两之间存在经过白边也经过黑边不经过重复点的路径,如果有,那么有且只有一对点对不可以。
-
CF843D 桶排 dijkstra 是线性的。
考虑加边权给最短路带来的影响,我们先跑全局单源最短路,将新的边权设置为 \(len-(dis_v-dis_u)\),也就是相对于最短路多走的部分,则 最短路是一条全零的路径,且若 增加部分边的边权,等效为增加新的边权跑最短路跑出来的最短路为答案增量,其实可以从流的角度理解,然后更新边权。
-
NOI2011 兔蛋游戏 博弈失误指当前存在必胜策略,失误后另一个人存在必胜策略。
二分图博弈存在必胜策略当且仅当这个点是最大匹配必须点。
-
HNOI 2018 省队集训 Day 5 Party 每一类物品每个人只能够总共拾取一个,这类很明显的匹配字眼一定要关注。匹配是图论常见思路之一
-
ZJOI2018 胖 贝尔福特曼算法的每个位置 \(p\),更新次数取决于有多少个 \(i\) 满足\([1,i-1]\) 长度的最短路长于 \(i\)。
-
朗道定理:在竞赛图中将出度从小到大排序后强连通分量个数为 \(\sum_{i=1}^n[\sum_{j=1}^iout_j={i\choose 2}]\)
-
判断平面图点 \(u,v\) 是否连通可以转化为是否在对偶图里存在环。
-
\(2^S\) 是很明显的分治提示。欧拉回路常用于均分,差不超过1等字眼 - CEOI Balance
-
异或,不进位加法。
-
CF2022E2 给定矩形 \(A\),若对于任意子矩形的四角异或和都是零,则说明存在数组 \(X,Y\),满足 \(A_{i,j}=X_i\oplus Y_j\),特别的若钦定 \(X\) 首项为零,则 \(X,Y\) 唯一。
-
一个排列可以在删除一个单调递减子序列后变为单调递增序列,则其充要条件是不存在长为四的子序列满足离散化后是
3412/2143 -
CF2025 F 给一个全零序列要求每次选择数+-1,且不能为负,最优话最终的和,那么+-1运算可以改为异或,没有顺序要求
-
CF2030 G2
给定若干区间 \([l_i,r_i]\),要求最小的点 \(x\),要求每个区间每次扩展 \(1\) 的代价是 \(1\),则要求所有区间覆盖 \(x\) 的代价之和最小。求最小代价。
- 将区间按照 \(l_i,r_i\) 分别排序,然后取 \(l_{\max},r_{\min}\)
- \(l_{\max}>r_{\min}\),将代价加上 \(l_{\max}-r_{\min}\),删去这两个区间,重复
- 否则跳出
-
CF2030 G2
得到组合数式子 \(f(x,y)\),可以 \(O(1)\) 移动端点,观察题目的单调性等要求,最不济也可以莫队。
-
ZJOI2019 开关
直接得出的暴力递推式,可能通过生成函数分析后可以给出相当简洁的结论。
-
跑没有重复边权的 \(2^x\) 边权最短路时,可以仅比较出边大小。
-
bitset 在底层(元素很少)时采用暴力形式能够减少复杂度。尤其是在元素个数 \(\le \frac{n}{w}\) 时。
-
高维前缀和一维一维推是没问题的,不会重。相当于每次钦定了最后依次失配的位置。
-
图的问题,可以从奇环/偶环/链推广到普通环和简单树,再推广到一般图
-
Kummer 定理,\({n+m\choose n}\) 中质因子 \(p\) 的出现次数为 \(p\) 进制下 \(n+m\) 的进位次数。
推广:
在 \(n!\) 中质因子 \(p\) 的出现次数显然为 \(\sum_{i=1}^{\lfloor\log_p n\rfloor}\lfloor\frac{n}{p^i}\rfloor\)将 \(n\) 表达为 \(p\) 进制为 \(\sum_{i=0}^{\lfloor\log_p n\rfloor}a_ip^i\),则 \(n!\) 里 \(p\) 的出现次数同样可以写为:
\[\sum_{i=1}^{\lfloor\log_p n\rfloor}\sum_{j\ge i}^{\lfloor\log_p n\rfloor}a_jp^{j-i}=\sum a_j\sum_{k=0}^{j-1}p^k=\sum \frac{a_j(1-p^j)}{1-p}=\frac{s_p(n)-n}{1-p} \] -
CF1117 G
笛卡尔树的构建,一个是单调栈法,一个是 ST 表维护分治法
从单调栈法中可以看出,我们事实上是在动态维护 \([1,r]\) 的笛卡尔树
又从分治法可以看出,当前 \(r\) 的祖先(单调栈内元素)里第一个(从小到大) \(\ge l\) 的元素,其右子树是整个 \([l,r]\) 子笛卡尔树根节点的右子树
获得左子树的信息可以倒过来做
-
处理同余式,可以先拿出模数与系数的 \(\gcd\) 使其互质方便计算
AGC063 D
\(x\equiv a+bk(\bmod c+dk),\forall k\in [0,n-1]\cap Z\)
取 \(g=\gcd (c,d)\),则 \(n\ge 2\) 时,\(g|b\),否则无解
将 \(a\) 拆为 \(a-(a\bmod g),a\bmod g\),后面的那个最后在答案的地方加上去即可
-
斐波那契数列在奇素数 \(p\) 的循环节 \(L|(2p+2)\),也就是 \(O(p)\) 级别,\(L(p^k)=pL(p^{k-1})\)
-
\(Fib_{n+m}=Fib_{n}Fib_{m+1}-Fib_{n-1}Fib_m\)
-
\(a|b\longleftrightarrow Fib_a|Fib_b,Fib_{\gcd(n,m)}=\gcd(Fib_n,Fib_m)\)
-
删掉一个边集 \(E\),使得原图不连通,可以如下判断:
- 建立 DFS 树,给每个非树边一个随机权值
- 通过树上差分,给每个树边的权值设为所有跨过它的非树边权值异或和。
那么 \(E\) 删掉后原图不连通,当且仅当存在 \(T\subseteq E\),\(T\) 的异或和为零。
-
关于矩阵带障碍行走可达性问题,可以考虑分治中线。
本题中给定一张带障碍的地图,每次询问能否从 \((x_1,y_1)\to (x_2,y_2)\),每次只能向下或者向右。
进行分治,找 \(mid\),划分询问,利用
bitset求出 \(L_{i,j,k}\) 表示 \((i,j)\) 能否走到 \((mid,k)\),\(R\) 同理。进行判断即可,\(O(\frac{n^3\log n+qn}{w})\)
-
适当地将 \(dp\) 定义的状态进行转化来简化问题
在分段问题中,另一种状态的设计是将当前最后一段的权值压进状态里面,方便合并与计算。
适当地交换,拆分 \(dp\) 定义的维度达到简化问题的目的
-
利用已知博弈论的结论进行新问题的状态划分与分解。
-
当 sg 函数涉及多元状态时,尝试划分等效状态,达到降低状态数甚至降低未知元的目的,这更加便于寻找规律与计算。
-
DP 过程中避免无用状态(不仅仅是无意义状态,也可以是无用转移和对答案没贡献的状态)可以极大程度上加速
-
静态离线区间/二维询问,分治法是不错的选择
可行性DP使用bitset
-
每个点度数不超过 2 的连通图不是链就是环
-
注意相对性和可差分性。一个区间 \([l,r]\) 的答案与 \([1,l-1],[1,r]\) 或者 \([l,n],[r+1,n]\) 的关系
相对意义上的不变也是可以的。
本题中,我们只考虑串 \(S,T\) 两个的不同位置个数,那么同时交换两串的位置对答案是没影响的,所以执行 \(S:[L,N],T:[R+1,N]\) 的答案等价于 \(S:[L,R]\) 的答案
- 线性基计数,考虑各类限制,一般只计数标准基
-
涉及二维偏序的散点修改,可以考虑分块套数据结构(线段树)
-
重返现世 带组合数系数的 dp,可以考虑加一个维度维护组合数的上标,利用加法公式把系数在dp过程中递推
-
树的连通块容斥方法
将边的贡献拆在子树里
一棵树的一整个子树有特征 \(\sum_{v\in V}deg_v=2|V|-1\),因为有一条边(子树根)连向外界
-
优化暴力dp的一个可行思路是 按转移条件分类,上述两题中,皆为分段问题,注意到当前段的状态仅有 \(\log\) 种,于是可以将转移条件(当前段贡献)来作为状态,减少状态数
-
CF2028F 注意转移里的等效状态和一定不是最优状态,都是简化问题的根源
-
在求 \(x\) 与 Trie 树上的 \(p\) 子树内所有值异或和的和,自然的会想到维护 \(p\) 的子树内每一个二进制位 \(1\) 出现次数。
但是这样空间是 \(\log^2 V\) 的,很劣,可以考虑对 Trie 做 dfs 序(亦或者插入时按递增顺序插入),我们只关心叶子,因此可以做差分查询。
-
对于一个排列 \(p\) 是原树 \(dfs\) 序的充要条件是(\(p_i\) 为 \(dfn_i\)) :\(\forall v\in Son(u),d_u<d_v,d_v+sz_v\le d_u+sz_u\)
只需要考虑每一对父子
-
数论题关注质数
找到一个尽可能优的状态并将其扩展
-
\(\max(a,b)=a+b-\min(a,b)\) 在计数上的基础运用。
-
-
设 \(d_u\) 为 \(1\to u\) 的最短距离,在树上增加一条边 \((a,b)\),让 \(\max d_v\) 最小。则 **加边端点至少其一是 \(rt\) **,可以通过说明 新增的每条路径,按照这个方案连都有一条不长与其的路径 来说明
-
\(h_i\) 为 \(\max_{dep_u>i,dep_v>i}dis(u,v)\) 可以通过树形dp和后缀 max \(O(n)\) 求出。
-
-
设括号序列,若 \(s[l_1,r_1],s[l_2,r_2],l_1\le l_2\le r_1\) 都合法,则 \(s[l_1,l_2-1],s[l_2,r_1],s[r_1+1,r_2]\) 合法
解决这样的合法关系,可以使用哈希的方法,将整个区间哈希一个独一无二的值,那么最终值相同的连续段就是极短合法段
-
一个序列的逆序对数的两倍一定大于等于 \([p_i\neq i]\) 的个数
-
线性基同样可以作为状态,当位数很小时,不妨研究其线性基个数(正交基)
-
研究路径上的第 \(k\) 大边权最小值——二分答案,变成01路径找最短路
-
CF1096E 条件概率 \(P(A|B)=\frac{P(AB)}{P(B)}\),可通过它转化一些限制
-
P11292
- \(cnt^m\) 的组合意义是有放回地取 \(m\) 个球
- 将所求答案表达为 \(f\),二项式反演后成为 \(g\),可尝试继续将 \(f\) 用 \(g\) 代换简化式子/发现可合并计算
-
P10004
将排列的升高与其上升段进行联系。上升段与极长上升段之间是二项式关系
计数排列 \(p\) 升高为 \(x\),逆排列升高为 \(y\),可以转化为一一对应的矩阵:
将 \(p\) 的上升段画出,\(p^{-1}\) 的上升段画出,按 \(p^{-1}\) 一个上升段一个上升段地将不断填入 \(p\) 的各个上升段
则设矩阵 \(a_{i,j}\) 表第 \(i\) 次填入时,将 \(p\) 的第 \(j\) 个上升段填入了 \(a_{i,j}\) 个数字。
排列可根据 \(a\) 还原。\(p,p^{-1}\) 的每一种极长上升段划分方式与矩阵 \(a\) 唯一对应。
而这个划分方式可以根据二项式反演回推出极长上升段划划分进而计数。
-
UOJ 310 当宁知道 \(xa+yb=s,a+b=t\) 时,宁可以求出 \(x^ay^b\) 对已知的 \(x,y\)。
-
二分图与容斥:二分图的导出子图
-
\([>]=[?]-[<]\) 容斥关系。Heoi2013 Sao
-
两两不等可以容斥为集合划分问题。ABC236EX
-
CF 2085F2
给出一个值域 \([1,k]\) 的数组,最少的 swap 次数让数组出现一个长为 \(k\) 的子区间满足是一个 \(1\sim k\) 的排列
枚举一个中心点 \(x\),最优解一定是将 \([1,k]\) 所有数字离 \(x\) 最近的拿出来将其聚集在 \(x\) 两侧最优。
代价计算是容易的。
中位数的考量
可以使用二阶差分做到 \(O(n)\)
-
CF 2081D
定义完全图边 \((x,y)\) 权为 \(\max(p_x,p_y)\bmod \min(p_x,p_y)\)
则首先值相同的是一个连通块,代价0.
其次对于每个值 \(t\),我们只让他在每个 \((kt,kt+t)\) 里找值最小的一个点,这条边保留,假设保留两个点的边,这两点互相连更优。
可以使用桶排,可以做到 \(O(V\log V)\)
不优决策的排除
-
CF 2075F
求 \(\max_{l,r}(\sum_{x\in [l,r]}[a_x\in [a_l,a_r]])\),\(a_l\le a_r\)。
与端点值密切相关的区间最值,考虑前后缀极值,也就是排除不优决策
因此只有前缀最小和后缀最大可能产生贡献。
则对于一个数 \(a_x\),其贡献就很简单了:\(a_l\) 属于某个矩形,\(a_r\) 属于某个矩形时产生贡献。
由于有前后缀极值的限制,就相当于是某个前缀最小值区间,某个后缀最大值区间产生贡献。
二维贡献,扫描线即可。
-
CF 2086E,进制问题,可以 将最高位有无作为划分状态的依据,变进制数一样的。
-
CF 2092E,统计方案时,微扰后查看奇偶性变化
-
CF 2089D,轮换操作,考虑看作一轮轮匹配。
-
CF 2077E
每次操作选出一条链:考虑建立出DAG,最小操作次数就是最小链覆盖就是点数减去最大匹配。
然后还有 Hall 定理等辅助判断。
-
CF2071 F
计算单个状态的答案使用简单dp。
同时计算多个状态的答案,要么使用轮换/对称性转化,要么就根据转移形式根据数据结构优化。
-
CF2077E 经典结论:任意折若干次纸带,在最终纸带上找一个位置滴下墨水,则被染色的格子按顺序排序后充要条件是相邻格子下标奇偶性不同。
-
CF1792 E
在枚举 \(ij=s\) 时,检查 \(\min(i)\) 与检查 \(\max(j)\) 是等效的。
-
CF1792 F
对于任意图 \(G\),其补图与其自身至少有一个是连通的。
假设 \(G\) 不连通,则其属于不同连通块的两个点之间都有边,则显然连通。
-
CF2056 D
一个偶数序列的前中位数和后中位数不同的充要条件是存在且仅存在一个 \(k\) 在原序列出现过且 \(\le k\) 的元素恰好有一半。
-
CF2056 E
线段集合,不交/包含——可建立笛卡尔树。
-
CF2096 F
在处理相关极值的三维偏序问题时可考虑主席树的不同建立方法比较。
如查询被 \([L,R]\) 包含的,编号 \(\le r\) 的最大编号。
应当以 \(R\) 排序建立主席树,以编号为下标存最大 \(L\)。
这样就可以变成求 \(rt[R]:[1,r]\) 中值 \(\ge L\) 的最大编号。
-
CF679 E
在判断一个序列 \(a\) 是否有元素的值属于某个集合 \(S\),支持区间加,可以考虑将 \(S\) 内元素排序,然后维护每个元素到 \(S\) 里 $\ge $ 它的最小值的差。
那么区间加就会变为区间减法,而对于 \(<0\) 的点暴力重构。
复杂度就是 \(O(n|S|\log n)\)。
区间赋值不影响复杂度。
-
CF1588 F
-
对于排列 \(p\),\(swap(p_x,p_y)\),相当于:两者同环时分裂,两者不同环时合并。
-
询问分块的优势在于:
-
将前面的操作提前计算出来。
-
预处理这 \(O(B)\) 个操作,可以划分等价类(往往 \(O(B)\)) 个。
-
考虑 \(O(f(n)+g(B))\) 的预处理,往往可以考虑 \(O(n+B^2)\) 之类。方便计算答案。
-
统计每个等价类对每个询问的答案,修改时对所有牵涉的等价类暴力修改。
每一步都是等价类个数级别的。
-
-
对于多个毫不相干的维度:例如区间&有向图连通性,区间&置换环,树&图,往往考虑 bitset,分块,根号分治等优秀暴力算法。
-
-
CF375 E
将限制条件列入 DP 状态。例如此题要求每个点至少有一个距离 \(\le x\) 的点是黑点,那么可以直接设出每个点最近的黑点进入状态。
在转移的过程中找限制条件(往往最优化问题可以忽略一些限制,但要排除不合法的状态)。
-
CF2097 E
使用数据结构维护多个过程的贪心转移。
在此题中,给出序列 \(a_n\),要求对每个 \(x\),拿出 \(a_i\le x\) 的点集排序,然后给定 \(d\),使用区间长度为 \(d\) 的尽量少的区间去覆盖所有点的个数。
考虑本质不同状态只有 \(O(n)\) 个,离散化后 (\(m\) 个值,设数组 \(b\)) 考虑线段树维护整体贪心。
首先让 \(m\) 个指针全部指向 0,接下来按位贪心:
设 \(S_i\) 为当前指向 \(i\) 的指针集合。
枚举:\(p:1\to n\)
- \(S_p\leftarrow S_p\cup S_{p-1}\)
- 对于所有的 \(x\in S_p,x\le b_p\),将 \(S_p\leftarrow S_p/\lbrace x\rbrace\),\(S_{p+d}\leftarrow S_{p+d}\cup\lbrace x\rbrace\)
-
“二进制分配”,考虑得到一个排列p,若能给出任意集合S,判断i是否在S中,那么可以按二进制位是否有1来询问,然后就可以知道某个值对应位置的这个二进制位
-
CF2101 E
关于树上路径的最优化DP转移(权值或者转移条件),可以考虑淀粉质优化转移,或许结合数据结构。
\[f_{u,i}=\max_{p(u,v)\le K}(f_{v,{i-1}}+w(u)+w(v)) \]这类物质,由于淀粉质的时候,按顺序加入各个子树的贡献并计算(然后倒着再跑一边)即可。
-
CF2101 B
对于排列 \(p\),每交换一对数,逆序对奇数变换。
例如每次操作 \(swap(a_i,a_{i+2}),swap(a_{i+1},a_{i+3})\)
则任意逆序对奇偶相同且奇数下标元素集合相同的排列都可以变到。
-
CF788C
如果钦定一个混合方案的浓度,那么可以将所有初始浓度减去要求浓度,然后每一份参与混合的溶液的浓度和为零 0
-
CF626F
当贡献只与某个组的类似“极值”有关时,可以使用连续段DP,通过值域从小到大转移。
-
CF1523 D
某个数被不少于 \(\lceil\frac{n}{2}\rceil\) 个人同时选中,则随机一个人有至少 \(\frac{1}{2}\) 的概率选中它。
找到一个最大的数集使得同时作为至少 \(\lceil\frac{n}{2}\rceil\) 的子集,则随机一个人枚举它所有子集,答案枚举不到的概率只有不超过 \(\frac{1}{2}\)
-
CF 917D
求完全图的生成树有多少个与某个特定生成树恰有 \(i\) 条相同边。
可以考虑使用二项式反演,也即在给定生成树上选择断边(也就是将其划分为不交的连通块),连通块之间连边用 prufer 序列,连通块之内是钦定选择的边。
可以发现这样的贡献恰契合二项式反演。
-
prufer 经典结论:\(n^{k-2}\prod_{i=1}^ks_i\)
-
CF 1868 C
对于堆式二叉树,本质不同的树的数量仅 \(O(\log n)\) 个,往往可以通过记忆化搜索进行处理。
-
ARC171 E
很巧妙的思想,将棋盘上不可同行同列的棋子将其画出横线或竖线表示玩跳棋时跳过棋子的方向。
-
ARC 162 D
在有编号限制的情况下,不妨将其作为DP维度,按编号大小考虑点
这样在生成一个方案时只会用到编号在某个范围内的点(DP使得)
-
ARC 165 E
从概率的角度以加入“无效操作思想”并不会影响实际发生的概率(傅里叶公式)
例如随机选一个可操作的点(点不可被重复操作,一个点被操作后可能导致某些点不能被操作)则可以转化为随机一个排列,逐个操作,遇到不能操作的跳过。
-
ARC 198 E
半在线 and / or 卷积:将 FWT 写为类分治FFT形式计算即可。
-
CF 1582 F2
通过减少不必要的转移,以及设计好的转移顺序优化DP。
-
CF 2109 F
网格图 \((n,1)\to (r,n)\) 的边/点权和最小的割可以由一个多源汇最短路得出。
-
ARC 196 C
计数问题。
将答案表达为 \(f_i\) 后考虑容斥半在线卷积转移。
-
UOJ 549
二进制位数切半法转移。
即 \(f_{i,a}=\max(f_{j,b}+w(a,b))\)
假设 \(w(a,b)\) 可以拆分:将 \(a\) 拆为 \((c,d)\),\(b\) 拆为 \((e,f)\),且 \(w(a,b)=w(c,e)+w(b,f)\)
则可以维护 \(f_{i,c,d}\),维护在列的每一种取值时行最值,这样直接 \(O(\sqrt V)\) 取出转移,然后再 \(O(\sqrt V)\) 地去更新转移。
实现上将二进制切半,涉及位运算相关代价函数。
-
P11292
\(a^2\) 的意义是有放回地抽取两次。
DP中走两条不相关的路,可以考虑不同时转移,而是先走完一条再走另一条,类似多维度卷积。
-
AGC033D
将答案作为一个维度,把dp转换为在取到某个答案时某个变量的最优取值。
同样可转移,适用于变量范围远大于答案的情景。
-
P3352
设计DP时,找到不变的量与有关的量。
让状态包含以后要转移的所有信息——封闭性。
如区间DP,要让所有涉及这个区间转移的信息全部被表达。
-
CF 708E
当计数类DP多维度难以优化时(往往 \(O(n^3)\) 起步)
限制只和 \(L,R\) 独立相关——不干扰。
不妨考虑维护行和与列和,看能否完整转移。
-
Gym 102059 C
两类小球一类往左一类往右相撞的计数类问题
枚举最终切点,划分两半处理,可能需要结合费用提前计算。
-
P8329
对于计数集合之间的强限制时,不妨考虑通过容斥减弱限制并赋予新的容斥系数进入转移。
-
CF 750G
一颗堆式线段树的一条路径,已知点编号和,左右链深度,则这样的路径LCA至多存在一个。
-
权值矩阵满足四边形不等式可以推出关于段数 \(m\) 的序列划分问题是凸的。
$A_{i,j}+A_{i+1,j+1}\le A_{i+1,j}+A_{i,j+1}\implies $ 定义 \(f(m):\min _{p_0=0,p_m=n,p_i<p_{i+1}}\sum_{i=1}^m A_{p_{i},p_{i-1}}\)
则 \((m,f(m))\) 是凸的。
若将矩阵 \(A\) 取相反数满足 “逆四边形不等式”算 max 也是可以的
-
最小费用关于流量下凸,最大费用关于流量上凸
-
证明凸性/得到凸性:考虑按照下标 \(\bmod p\) 分类考虑,常用 \(p=2\)。
证明时,考虑这个下标每增加 \(p\),所需方案的关系(如果方案完备,也就是所有 \(x\to x+kp\) 的方案,都可以分组为每次增加 \(p\) 一共 \(k\) 次) 以及增量关系。
-
对于 \((a,b)+(c,d)=(a+c,b\oplus d),b,d\in \lbrace 0,1\rbrace\) 的问题,可以分治做闵可夫斯基和。
-
设 \(w(l,r)=\min_x \sum_{i=l}^r|a_i-x|\),\(a_i\) 递增,则 \(w(l,r)\) 满足四边形不等式。
-
多次区间询问一个凸性DP的解(通常会限制取若干段),考虑使用线段树预处理该段区间在 \(l/r\) 的不同限制条件下(取与不取),取 \(i\) 个的最优解。
线段树预处理时,采用闽可夫斯基和归并,\(O(n\log n)\),询问时,对于取 $k $ 段的限制再用 WQS 二分消去。可以使用整体二分,线段树上维护指针降低复杂度至 \(O(n\log n\log V)\)。拼接答案时采用一个 \(O(\log n)\) 的 \(dp\)。
-
利用分治应对带简单限制的闽可夫斯基和。P11459
-
设答案为 \(x\) 时代价为 \(f(x)\)(单增减),求限制最大代价的最优答案,而 \(f(x)\) 不好直接计算,若 \(f(x)\) 有凸性,可以考虑 WQS 二分。ARC168E
-
CF2115E
-
转圈法解同余最短路
-
大容量完全背包有结论:最多有 \(w_x\) 个物品不选性价比最高的那个,其中 \(x\) 是性价比最高的物品,\(w\) 是其重量。因为选的所有物品除了 \(x\) 必然 \(w\bmod w_x\) 不同。因此最多有 \(w_x \times \max w\)
的背包不选性价比最高的。
-
-
CF 1976 F
长链剖分经典结论:在树上选出 \(k\) 个点,包含它们的连通块大小最大,包含根节点,则选最长的 \(k\) 条长链。
事实上若不要求包含根节点,则以直径一端DP即可。也可以动态维护直径,然后将整条链改为0。
-
CF 1225 F
给出一条链,每次将一个点的父亲设为父亲的父亲,则构造成给定形态的树只需要 \(n-\max dep\) 次,并且给定树的 dfs 序可以作为这条链的编号(\(x\) 在链上第 \(dfn_x\) 个位置)
-
CF 860 E
栈与二次排序建立虚树的本质。
-
CF1575 E
长链剖分的一种实现是借用 vector swap \(O(1)\),因此每次 dfs 时若发现新儿子的 vector 更长就 swap。
-
CF2115 E
有 \(m\) 个物品,每个物品无限个,体积 \(v\) 与价值 \(w\),而有容量 \(m\) 的背包。
则至多选取 \(\max v\) 个非最高性价比的物品( mod 运算的意义)。方便应对 \(m\) 极大的情况。
大容量多重背包结合有向图的经典问题。
转移考虑裴蜀定理以及 lcm,gcd。
-
CF 2115 D
很巧妙的博弈神似线性基的问题。
技巧:给出序列 \(a,b\),需要对于每个 \(i\),要么选出 \(a_i\) 要么选出 \(b_i\) 通过求和/异或达成某种目的(以 xor 为例),先算出 \(a_1\oplus a_2\oplus\dots\oplus a_n\) 变为必选这个数,其他数 (\(\lbrace a_i\oplus b_i\rbrace\)) 可选可不选
-
A:珠宝:按 \(c\) 分组转移,每组内部排序,当处理到第 \(i\) 组时,按下标 \(\mod i\) 分为 \(i\) 组,每组间有决策单调性,分治转移即可。
-
B:gym102586B 注意到分离变量l,r后有决策单调性(四边形不等式)
考虑离线算法,如何高效处理。将决策点区间化到线段树上,线段树上每个点统一处理。
这是一个通法:将 \(q_i:[L_i,R_i]\) 的询问,拆分区间到线段树上,以附加 \(O(\log n)\) 的代价换来了整体处理查询的机会。
-
平衡树是维护凸包的最泛用工具,在合并时采用启发式合并即可做到 \(O(n\log^2 n)\) 复杂度。
-
连续性的凸包合并 P6893。合并两个凸函数为一个凸函数时(闵可夫斯基和),采用等效函数法,往往需要利用导数。
如在 \(x\in [0,n]\) 的两个形如 \(ax-bx^2\) 的上凸二次函数合并时,首先暴力取暂时领先(即在 \(>0\) 的位置)的那个的领先部分,剩余部分可以化为一个新的二次函数(先去掉领先部分的两个新二次函数,此刻 \(a_1'=a_2\))。
然后假定函数移动 \(c_1,c_2\),就有:
- 求导后这个点导数相同
然后可以算出新函数。
例子:用 \((a,b)\) 记录 \(ax-\frac{1}{2}bx^2\)
则 \((a,b_1),(a,b_2)\) 合并时,假设其移动量分别是 \(c_1,c_2\),就有:
- \(a-c_1b_1=a-c_2b_2\implies c_1=b_2x,c_2=b_1x\)
- 变化量 \(a(c_1+c_2)-\frac{1}{2}(b_1c_1^2+b_2c_2^2)=a(b_1+b_2)x-\frac{b_1b_2}{2}(b_2+b_1)x^2\)
- 移动量 \(c_1+c_2=x(b_1+b_2)=\Delta x\)
所以在 \(\Delta x=b_1+b_2\) 时,变化量为 \(a\Delta x-\frac{1}{2}\frac{b_1b_2}{b_1+b_2}\Delta x^2\)
因此可以得到 \(a'=a,b'=\frac{b_1b_2}{b_1+b_2}\)
-
P8864
- 操作 \(i\):\(a'_{i-1}=a_i\oplus a_{i-1},a_{i+1}'=a_i\oplus a_{i+1}\) 等效为交换 \(i,i-1\) 的前缀异或和。
- 蒙日矩阵的 \((\min,+)\) 矩阵乘法等效于二维四边形不等式 dp,可以做到 \(O(n^2)\)
-
P1721 另类的斜率优化:\(f_{i}=\max (\frac{f_j+w_i-w_j}{i-j+1})\) 状物,仍然可以画图分析得出凸壳 存点 \((i-1,w_i+f_i)\),仍然可能成为最优解的元素构成下凸壳。与此同时还可以论证如果队头目前不是最优以后也不会是,因此可以直接弹 出队头。
-
凸壳思想不仅仅用来优化DP,其本质是一种最优决策点寻找方法 ABC373F CF1575M
-
ARC183F
一棵树存在完美匹配,当且仅当:
- 称 \(sz\) 为奇数的点为 1 类点,\(sz\) 为偶数的为 \(0\) 类点。
- 根节点是 \(0\) 类点。
- \(0\) 类点恰有一个 1 类点儿子。
- 1 类点的所有儿子都是 0 类点
同时删除两个叶子,仍然存在完美匹配的条件是:这两个叶子的路径是一条两端为 \(1\),且 \(01\) 交替。删除后,除了 lca,其余点全部翻转类型。
以重心为根,可以将节点按顺序两两配对,使得按顺序操作后,每次都是删两个路径过重心的叶子(dis 之和取到最大)
考虑重心一颗子树的删除顺序。其实是优先递归 \(1\) 类点儿子,然后递归 $0 $ 类点儿子,最后的出栈序的逆序。
每次取 sz 最大的两个儿子,将其删除各自子树内删除优先级最高的叶子取出配对。
-
ARC095F 对于一颗边可以转化为 \((premx_{i-1},p_i)\) 其中 \(p\) 是一个排列。
这样的时候,\(premx\) 会组成树的直径(可能会多衍生出来一个)
其他点都挂在这条链上,也就是一个毛毛虫。
-
AGC024D 对于一棵树,在进行任意的加点后,以不同节点为根的同构有根数最少只有 \(\lceil \frac{l}{2}\rceil\),\(l\) 是直径上的点数,这个上界可以取到。取出直径中点以其为根,然后将每一层的节点数都扩充到当前层儿子最多那一个,这是加点下界。
-
ARC 117 F给定树,对于一个序列 \(E\) 满足 \(|E_i-E_j|\ge dis(i,j)\)
有将 \(E\) 排序后:
\(E_i-E_{i-1}\ge dis(p_i,p_{i-1})\)
\(E_i-E_{i-2}=(E_i-E_{i-1})+(E_{i-1}-E_{i-2})\ge dis(p_i,p_{i-1})+dis(p_{i-1},p_{i-2})\ge dis(p_i,p_{i-2})\)
所以只需要相邻项满足即可。
最小化 \(\max E\),也就是使得一条走过所有点的路径最短,明显是每条边两次(回到起点),再减去直径。构造是容易的,dfs ,最后遍历直径即可(不需要回溯)。
-
P1232
对于一颗有根且儿子访问顺序固定的树,其 dfs 序与其 bfs 序的信息非常丰富。
现给出 dfs 序与 bfs 序 求所有满足这样的树的高度的均值。
设 dfs 和 bfs 为 \(d[i],b[i]\),其逆排列分别为 \(a,c\),本质上是找 \(b\) 中平均分层断点个数。
-
\(0\le dep[b[i+1]-]dep[b[i]]\le 1\)
-
若 \(a[x]<a[y]\),但 \(c[x]>c[y]\)
说明x,y没有祖孙关系,也就说明x对应的子树不会超过 \(a[y]-1\)
若 \(a[x]<a[y],c[x]<c[y]\)从考虑一般情况到考虑相邻情况,由相邻扩展到两端
-
bfs 相邻两个,要么跨层要么兄弟要么就跨子树
dfs 相邻两个,要么儿子要么就回溯成某祖先的兄弟 -
\(a[b[i]]+1=a[b[i+1]]\):应该是没限制
如果不分层,则 \(b[i]\) 不能有第二个儿子 -
\(a[b[i]]>a[b[i+1]]\):说明b[i]与b[i+1]没祖孙关系
这里有问题啊,对于这两的LCA来说,如果同层,dfs先走b[i+1]一侧,bfs先走b[i]一侧
这是有问题,说明在两者间存在分层(一定)。 -
a[b[i]]+1<a[b[i+1]]:说明是同层点
扩大一点范围呢?发现可行情况变多,且限制变松,
而对于不能有第二个儿子的限制该怎么说呢?其实也就是说对于有固定儿子就不能发生这类情况,因为这种可选儿子只会有一个,且作用于没有固定儿子的情况。
什么时候有固定儿子?手玩可以发现,固定为儿子的情况只有:可以看到是dfs相邻的两个点:\(x,y(dfs_x+1=dfs_y)\),在bfs中,若 bfs_x<bfs_y-1,则这遍历中连着的两个点 \(y\) 是 \(x\) 的儿子,仅此一种可能。
可以将这个利用差分打区间标记,表示 \([bfs_x,bfs_{y}-1]\) 有且仅有一个位置会分层。而这个分层位置已经是我们提前找到确定的,每一段区间一定会有且仅有这样一个位置。
-
-
P3971
给出一个序列做 LIS 后的 dp 数组 \(a\),要求对于所有满足这数组的序列,设 \(f_i\) 为以 \(i\) 开头的最长下降子序列长度,球 $\sum f_i $ 的最大值。
有如下信息:
- \(i<j,a[i]\ge a[j]\) 则 \(p[i]>p[j]\)
- 对于 \(i\),至少有一个 \(j<i,a[j]=a[i]-1\),且 \(p[j]<p[i]\),
如果有多个,则必然按递减顺序排列且最后一个一定满足 \(p[j]<p[i]\)。那么我们就只知道: - \(i<j,a[i]\ge a[j]\) 则 \(p[i]>p[j]\)
- \(i<j,a[i]=a[j]-1\) 且 \(i\) 最大,则 \(p[i]<p[j]\)
如何最优化 \(\sum f\) ?直觉是让后面尽可能小,也就是尽可能从后往前,从小到大
只考虑第二个限制,让后面的尽可能小怎么样?
考虑两个排列,若只有两个元素不同,谁更优?
显然是小的在后面更优。那么我们根据 \(a_j=a_i-1\) 且 \(j<i\) 的最大 \(j\) 进行连边,容易发现权值只需要满足这样一棵树就行了。
相当于给了一颗内向树,其中根节点是0,子节点大于父节点。
那么考虑如何分配
一个想法是利用优先队列做广搜,每次搜出编号最大的给出最小的值。这是对的,证明?
本质上,我们是希望 \(v-1\) 给到的位置大于 \(v\)。这样搜,满足原序列的拓扑序,且让小的尽可能出现在大的后面。
-
CF 1804F
- 当允许输出答案 \(p\) 满足 \(p\le 2ans\) ,而 \(ans\) 随时间减小时,答案序列的 $p $ 就不会超过 \(\log V\) 种了,即使有一个 \(p\ge ans\) 等类似的下界限制。二分当前答案所在的那段时间轴,然后看下一段找新的答案和范围 都是一个好的想法
- 对于一张图,最远点对的距离不超过 \(2d_x\),其中 \(x\) 任意取,\(d_x=\max dis(x,y)\)
-
ARC156C
对于一颗树,存在一个排列,使得对于树上任意路径,其点编号构成的序列与其中点的排列值构成的序列的 LCS 最大为 1。
构造方案是对于任意一个置换环,希望其如果被某个路径包含了所有点,那顺序也是反的。
因此,所有置换环尽可能小会更优,那么构造方案就是以重心为根,每次取出两个叶子 \(x,y\),设置 \(p_x=y,p_y=x\)
-
设 \(d_i=\sum dis(x,i)\) ,前提 \(d\) 互不相同。
-
如何构造这样一颗树?
注意到重心 \(d\) 最小,而 \(d\) 最大的必然是叶子,所以从大到小,处理 \(sz\),并根据 \(d_{fa}+n-2sz_i=d_i\) 找到了父亲
注意最终只满足了 \(\Delta d\) 的限制,在处理过程中维护真实的 \(d'\) 值即可。
-
ARC140D
对所有情况下的图的连通块数进行求和,不妨转化为每个可能连通块会在多少个局面中出现,进而找一个连通块的本质特征会在多少个局面中出现。
在本题中,由于一个确定局面,每个连通块都是基环树,那么一个固定形态的环就是一个连通块的标志,即所有情况下的连通块数,等于每一个可能形态的环的出现次数的和。在本题中,对于已经确定的环,可以立即给出存在的局面数(那些 \(-1\) 任意填即可),而对于不确定的环,它由原图中若干个不确定的树(仅有树根不确定),按一定顺序(圆排列) 组成(每个树根往下一棵树的任意点连接,这样各个树根的路径会形成一个环)。并且这所用的 \(-1\) 个数也就是树的个数,其局面数同样容易计算。
-
CF1499F 在划分树连通块时,若对直径有限制,不妨将当前连通块根往下最长链作为一维状态,直径可以被合并子树时表达出来。
-
CF2122D
在如下情景中,答案不大于 \(2n-3\)
给出一张简单无向连通图,在第 \(i\) 秒,对于每个点 \(x\),仅有它出边的第 \((i\bmod deg_x)+1\) 条能用,从点 \(1\) 到每个点的最短时间都不超过 \(2n-3\)。
所以可以 \(O(n^2)\) 计算出耗时最短时最少等待时间。
-
CF2122E
- \(2\times n\) 的网格走路问题,可以设 \(c_i=a_{0,i+1}-a_{1,i}\),则任意只能向右或向下的 \((0,0)\to (1,n-1)\) 的路径,可以用 \(a_{0,0}+sc_x+\sum_{i=0}^{n-1} a_{1,i}\) 表示 \((0,0)\to (0,x+1)\to (1,x+1)\to (1,n-1)\)
它将跨越两行的路径比较,拆出了常数,化为了一个序列的前缀相比较。
-
对于一个 \(f(z)\times g(z)\),若 \(g(z)\) 的每一项系数可以被一个 \(k\) 次多项式表达,则可以 \(O(nk^2)\) 计算。
具体地,考虑目标 \(s=i+j\),将 \(g(z)\) 系数表达的多项式里的每一项未知数替换为 \(s\),可以得到每个幂次所对应的系数多项式,它应当以 \(s\) 为未知数,原系数表达多项式配凑出系数,最终可以化为将幂次乘到 \(f\) 里,通过前缀和计算答案。再根据结果多项式的每一项的指数来计算这个每个前缀和相应系数
例如当 \(f(z)\times g(z)=h(z)\),其中 \(g(z)=\sum (b+ki)z^i\),则有:
通过维护 \(i\times f_i\) 以及 \(f_i\) 的前缀和即可计算。
当 \(g_x\) 为一次函数可以这样,则更高次同样可以。
-
arc202 B
-
当你发现偶数时情况与奇数不同,不妨打表查看情况。
-
一个排列 \(p\),对于一个排列 \(q_i\),满足 \(p_i-q_i\equiv 1/-1(\bmod x)\),且 \(p\) 长为 \(x\),则当 \(x\) 为奇数时,\(q\) 只能被整体加一或整体减一,偶数时,\(p\) 中的奇数项与偶数项各自独立 \(\pm 1\)。
-
延续上一条,经过 \(h\) 次变换后,\(q_i\) 再次变为最开始的 \(p_{i+1}\)(循环),则 \(x\) 为奇数时,\(p\) 必须是等差的,且公差与 \(x\) 互质,当 \(x\) 为偶数时,相当于做 \(2h\) 次变换,\(q_i\) 变为 \(p_{i+2}\),那么这就要求第 \(i\) 行与第 \(i+2\) 行是等差的,且公差与 \(x\) 互质(偶数类行与奇数类行公差一致),只需要满足这个限制即可(也就是说,第一行第二行公差虽然一致,与(3->4,5->6 等一致),但可以和 2->3,4->5 等不一样,只需要 1->2+2->3 与 \(x\) 互质即可)。
-
-
arc202 C
若数列 \(r\) 满足 \(\gcd(r_n,r_m)=r_{\gcd(n,m)}\),则通过指数的min-max容斥(gcd-lcm关系探究常用),可以得到:
设 \(r_n=\prod_{d|n}f_d\),这可以通过 \(r\) 反推得到。
则 \(lcm(r_{a_1},r_{a_2},r_{a_3}\dots r_{a_n})=\prod_{\exists i,d|a_i} f_d\)
-
ARC126D 在选取子序列的dp状态时,需要设计出一个状态,足以计算不选择和选择分别的代价。例如在此题中选出一个子序列作为 \(k\) 的排列,代价是选出这个排列所需要进行的交换相邻元素的最小次数以及这个排列的逆序对数,则我们状压已经选了哪些,则可以根据是否过半来判断跨过这个元素的是从左往右还是从右往左,如果要选择,可以直接计算逆序対。
-
LOJ2351 毒蛇越狱
重要技巧:给出 \(0\sim 2^n-1\) 后,给出若干二进制位取值后,求符合的位置的信息和,如果支持差分,则可以根据这些限制里,\(0/1/?\) 的个数,选取最少的那个进行处理,使用子集和,超集和的技巧差分出解。
-
P7024 \(\lim_{n\to \infty}N{n\choose k}/n^k=N/k!\),本质是一个下降幂,下降次数确定的函数的复合后最高次项系数确定,就是取大小为 \(k\) 时,总方案数除掉 \(\frac{N}{k!}\)
-
CF1103 D
一车简化状态。这里有三个常见的手段。
- 划分同类数字:首先给元素划分等价类,将元素等价,价值不同的物品放一组,贪心DP。
- 抓住只会取不超过 \(c\) 个数字,当 \(c\) 很小时,将每个等价类只保留最优的 \(c\) 个。
在本题中,首先将所有数字圈定到对答案产生影响的质因子,划分第一次等价类,同时最多取质因子个数个元素,因此 \(c\) 很小,每一类数字保留代价最小的 \(c\) 个。
其次根据转移划分第二次等价类,对于消去每个质因子组成的集合的转移,只保留与这个集合有关的最优的 \(c\) 个。
-
加入逆否命题,这样折半后只需要考虑第一部分对第二部分的限制,不需要反过来考虑
那么折半枚举第一部分,稍加一些预处理后就是毒蛇越狱了。
-
CF2128E2
称一个整数数组的中位数集为能够成为这个数组中位数的整数集合。
那么我们声称给这个数组再任意增加一个元素,新的中位数集与原本的中位数集在值域上有交或相邻(也就是存在一个数 \(x\) 存在于旧中位数集,则新中位数集包含 \(x,x-1,x+1\) 至少一个)。
因此,对于所有可能成为数组 \(a\) 含某些限制的子区间中位数的整数,可以由数组 \(a\) 的符合条件限制的最小子区间中位数走到符合条件的最大子区间中位数的过程包含了所有可能的值。
-
CF2119E
给出数列 \(a,b\),每次操作选择一个 \(b\) 增加 \(1\),满足 \(a_i=b_i\&b_{i+1}\),考虑对于每个 \(b_i\) 可能取的值?
\(b_i\) 首先必须是 \(a_i|a_{i-1}\) 的超集,且对于 \(b_i\) 而言,若将某个二进制位从 \(0\) 改成了 \(1\),则更低的位只能于 \(a_i|a_{i-1}\) 相同最优。因此只有 \(O(\log V )\) 个取值。
-
CF2125E 对于一类数组计数,若太过困难,可以考虑一些变换规则,例如前缀和差分等。
-
猫树分治本质就是静态的,每一层合并可以从线段树 \(O(1)\) 变成 \(O(len)\) 即可。如果可以离线,则可以在猫树分治的过程中则可直接回答询问。
-
P8885 当需要简单的线性 DP 判断一个序列的合法性(或者说值域很小),并且需要求整个区间的合法子区间个数时,考虑将线性 DP \(f_{i,0/1/2\dots }\) 只会从 \(f_{i-1,0/1/2\dots}\) 这一类的,将 \(\lbrace f_{i,0/1/2\dots },0,1,2,\dots\rbrace\) 作为一个状态(所以状态数很少)(可以看作将原 dp 看作一个线性DP,做DP套DP)。
此刻若需要统计整个序列 \([1,n]\) 的子区间的合法个数,就可以设计 \(dp_{r,?}\) 为当前以 \(r\) 结尾的状态为 \(?\) 的 \(l\) 个数。\(dp\) 转移显然是一个矩阵。
-
统计一个区间的合法子区间个数,一方面是用扫描线,但若遇到需要DP这类复杂问题就不行了,可以考虑分治,枚举 \(mid\) 处的中间状态 \(?\),往左往右做 逆/正向 dp,然后将两边终态的和再乘起来计入答案。
事实上也可以将 dp 看作矩阵形式,对 \([l,mid],[mid+1,r]\) 利用结合律算。只不过为了省下空间可以枚举合并时的中间状态。
-
P6604
经典问题:如何求出 \(L\in [l,mid],R\in [mid+1,r]\) 的所有区间 \([L,R]\) 的最小值之和。
利用可持久化 segbeat 是可以可以容斥做的,但利用猫树分治可以做到 \(O(n\log n+q)\) 和强制在线。
注意到分治过程中,可以维护 \(x\in [l,mid]\) 对 \([mid+1,r]\) 的答案总和以及 \(y\in [mid+1,r]\) 对 \([l,mid]\) 的答案总和。
则可以考虑容斥出 \([l,r]\) 的答案,需要思量 \([l,r]\) 最小值属于哪一边。
以在左半为例,首先算上 \([l,mid]\) 的所有答案。那么对于 \([l,L-1]\) 的部分,事实上是 \((R-mid)\) 乘以 \(x\in [l,L-1]\) 的 \([x,r]\) 的最小值之和。
右半同理,其核心是利用了超出区间后,最值所在那一半后面的发展取决于自己而与限定的右半无关仅作为一个系数。
-
P8528 铃原露露。当正面的支配点对难以找到/可以证明难以/不可能将合法状态划分为合理个数的等价类(例如 \(O(n^2)\) 个)
那么就需要寻找反面的支配对,例如本题中,当 \({lca(x,y)} \in [x,y]\) 时包含 \([x,y]\) 的区间全部非法,则可以枚举 \(lca(x,y)\),然后启发式合并子树时枚举较小子树里的 \(x\),若 \(x<lca(x,y)\) 则找 \(>lca(x,y)\) 的最小 \(y\),否则找 \(<lca(x,y)\) 的最大 \(x\),这样就形成了 \(O(n\log n)\) 个标记非法状态的支配对了。
-
P12195 如果将欧拉序视作对 “边” 的标记,则一棵有根树存在一个欧拉序满足给定序列 \(x_1\dots x_m\) 是某个欧拉序的子序列,其充要条件是以 \(rt\) 作为 \(x_0\),走 \(x_0\to x_1\dots \to x_m\) 满足每条边都只经过最多两次。
-
P12018 转化后相当于给出一颗笛卡尔树,满足 \(i-1,i+1\) 不是 \(i\) 的儿子就是 \(i\) 的祖先(也就是正常对 \([1,n]\) 建笛卡尔树),每次问整个笛卡尔树需要选多少个在 \([L,R]\) 内的点可以满足对 \(i\in [L,R]\) 不是自己被选就是后代被选。
处理出 \([l_i,r_i]\) 表示自己的祖先的编号范围,那么直接从 \(L\) 开始跳,每次跳到 \(l_j>r_i\) 的最小的 \(j\),那么一定满足 \(l_j=r_i+1\)。这样跳的正确性显然。利用倍增预处理即可。
-
QOJ 4420,给定 DAG,多次询问只保留 \([l,r ]\) 的边能否从 \(u\to v\)。
可以考虑利用 bitset 给每条边处理出自己满足多少个询问的要求——这个的处理其实就是在扫描时 \(l_i\) 的时候将 \(i\) 位置为 \(1\),在 \(r_i+1\) 的时候再置为 \(0\),然后每个点处理出自己能在那些询问的限制下到其终点。倒着转移处理即可。
为了空间,可以考虑对原本的扫描时的状态分若干段,只存段头,然后询问的时候找最接近的一段再扫一遍。
-
ARC199A 给定01矩阵 \(a\),构造 \(X,Y\) 序列,满足新矩阵 \(b_{i,j}=a_{i,j}\oplus X_i\oplus Y_j\) 满足行和列和要求,且行和列和小于 \(\frac{n}{4}\)。
注意到可以钦定 \(X_1=0\),因此考虑第二行,若决定了 \(X_2\) 的取值之后,对于两行不等的列,无论 \(Y\) 如何取都是对两行总和有 \(1\) 的贡献,且两个取法对应的不等的列和为 \(n\),若不等列个数 \(\ge \frac{n}{2}\) 则两行至少其一不合法,因此 \(X_2\) 取法唯一,以此类推。可以不必分散目光与行列关系,仅对其一进行分析
-
CF725F
一个模型:
给定 \(n\) 叠照片,每叠两张,每张对 \(A,B\) 二人分别的贡献是 \(a_i,b_i\),对于每个人,其在每一堆的最优策略都是争抢第一张,目的是让自己权值和超越对方最多,求最终 \(A\) 的权值和,\(A\) 先手。
可以考虑到双方会争抢对自己最有利的第一张,抢完了再对第二张用相同策略。
这种情况就要想办法剥离第二人影响,也就是将其转化为第一人取计入贡献,第二人不取不计入贡献这种只考虑一个人的情况。
也就是说,一张照片取了贡献 \(a_i\),不取贡献 \(-b_i\),则考虑假定所有都取了,将扔一张的代价设置为 \(a_i+b_i\)。
在本题中,一叠照片 \(a_1,b_1,a_2,b_2\),最优策略都是争抢第一张的情况下安祖 \(a_1-b_2\ge a_2-b_1\),因此 \(a_1+b_1\ge a_2+b_2\)。
因此将照片按 \(a+b\) 从大到小排序,依次扔掉次大,次次次大……即可。
-
P3546
对于 \(S[l,n-l+1]\) 的最长 border 最多比 \(S[l+1,n-l]\) 长 \(2\)。
-
P4898
给定一个01矩阵,[所有的0构成一个矩阵]=[左上都是白点/边缘的黑点个数+四连通至少有两个黑点的白点个数=1]。
由此,可以 \(O(1)\) 判断,那么就可以用线段树维护,做到将一个全0/1的矩阵逐个翻转(不重复操作)整个操作过程中某一段时刻所达到的所有 \(0\) 构成一个矩阵的时刻个数,且支持操作序列的 swap。
经典的应用场景是给出一个矩阵每个点编号唯一,问 $ k\in [l,r]$,有多少个 \(k\),满足编号为 \([0,k]\) 的点能否恰好构成一个子矩阵。可以支持两个点编号的交换——每个点为白/黑的时间仅为一个区间,且每次改动不超过 \((4+1)\times 2=10\) 个点。
-
P7230
对于插入删除其一容易另一困难的区间问题,可以考虑线段树分治存在/不存在时间,并用另一数据结构维护信息。
-
P8476 当DP数组难以维护,不妨考虑维护其差分/前缀和,若复杂情形可以考虑先打暴力再修改。
-
P10196 线段树二分可以 \(O(\log n)\) 的做关于 \([1,n]\) 某单点的前后信息维护,可以利用传地址等实现方法。
-
CF1373G Hall 定理。人 \(i\) 可以在 \([a_i,\infty]\) 入座,求最小的 \(n\) 使得 \([1,n]\) 可以给每个人分配座位,其充要条件就是 \(\forall j,n\ge j-1+\sum [a_i\ge j]\),可以使用线段树维护。
-
CF1270H
可以在时间轴/值域轴上建立线段树进行维护。
判断时刻 \(i\) 序列是否呈 \(1111\dots 110000000\dots 0\) 形式,可以考虑对于每个 \(10\) 的存在时刻进行扫描线,这样还支持单点修改。
经典操作:给定序列 \(a\),单点修改,保证任意时刻元素不同,求 \(\sum_{i=1}^{n-1}[premn_i>sufmx_{i+1}]\)。
对于时刻 \(i\),将 \(> i\) 的元素置为 \(1\),其余为 \(0\),那么 \(i\) 合法当且仅当这个序列在这个时刻呈现 \(111\dots 1000\dots 0\),且存在一个 \(j\),\(a_j=i\)。
那么对 \((a_i,a_{i+1})\) 考虑其在时间轴上只有 \([a_{i+1},a_i-1]\) 的时刻呈现为 \(10\)。只需要区间修改查最小值即可。
CF2147 F 同理,在维护最小值时同时维护 \(\sum {pos_i-pos_{i-1}\choose 2}\),其中 \(pos\) 为最小值位置。类似此题与 1209G2 的结合版。
-
CF 2138 D
对于滑块类问题:将滑块 \(i\) 移动到位置 \(p\) ,撞到的滑块依次右移。
首先所有块的相对顺序不变,因此可以将 \(pos_i\leftarrow pos_i-i\),这样就变成了撞到的块会叠在一起,也就变成了简单的 \(\min,\max\) 运算。
-
P9990
关于奇偶性的区间统计问题,可以考虑开一棵奇数线段树和一颗偶数线段树,遇到奇偶性交换就直接 swap 线段树节点,遇到对某一 奇偶性的单独操作就在那棵树上改。
-
CF1572 F
在 segbeats 里,对区间最大值的统一修改是一个相当独立的过程,可以依次批量修改一堆东西。
例如设 \(b_i=\sum_{j=1}^i[r_j\ge i]\),我们对 \(r\) 做区间取 \(\min\) 时,在 \(segbeat\) 的修改时,直接将 \([l,r ]\) 中最大的 \(r_j\)(值相同)全部统一将影响范围缩小为 \(r’\),对 \(b\) 自然也就可以使用树状数组维护了,支持扩展为单点修改。
-
CF2144E2。复杂DP优化一定要先写出暴力DP式并确认正确后再开始优化,否则会调崩
-
CF2144F。对于 \(n\) 个长度不超过 \(k\) 的合法括号序列,若不包含 \(()\),则每一个串都至少不是这两者 \(()()\dots (),(((((((\dots )))))))\) 之一的子序列。
-
CF2140F。离谱的数学题。
关键结论:对于 \(p\in [2,n-1]\),若序列 \(a\) 存在 \(a_i\neq a_j(\bmod p)\),则必然存在一个长为 \(p\) 的子序列,满足 \(sum\bmod p\neq 0\)。证明:删掉 \(a_j\),在选 \(a_i\) 的基础上任选其他数字,若 \(sum\bmod p=0\),则将 \(a_i\) 换为 \(a_j\) 即可。
-
CF2147E 经典贪心:
给出序列 \(a\),现在可以使用 \(1\) 的代价将 \(a_i\) 增加 \(1\),给出 \(S\),求最小的代价满足:\(S\& (\big |_{i=1}^na_i)=S\)。
从高位到低位贪心:
设当前在处理第 \(t\) 位。
- 将所有数字 \(>t\) 的二进制位变为 \(0\)。
- 若 \(S\) 的第 \(t\) 位为 \(1\),找到所有数字的最大值 \(a_x\)
- 若 \(a_x\) 的第 \(t\) 位为 \(1\),则跳过。
- 否则答案加上 \(2^t-a_x\),将 \(a_x\) 置为零。
-
CF2146F
- 设 \(f_i=\sum_{j<i}[p_j>p_i]\),则冒泡排序执行轮数为 \(\max_{i=1}^n f_i\)。
- 当 \(n\) 很大但限制条件 \(m\) 很小时,考虑对 \(dp\) 做线性变换(前缀和差分等),减小维护的 \(dp\) 值数量(尽可能从 \(f(n)\) 变为 \(f(m)\))。转移可以考虑整段合并转移系数。
-
给出数组 \(a,f\)。
对于一个对 \(a\) 做背包的 \(dp\),最终对每个 \(k\) 算 \(\max(dp_i+f_{k-i})\) 这个卷积。
可以直接将 \(f\) 数组当作 dp 初始值。
暴力合并卷积的复杂度是 \(O(n^2)\),但背包复杂度可能比这个低,这个时候就需要运用这个技巧了。
-
CF1237F 计数技巧。
当将元素放入棋盘,对于每个元素有占据一行两列和一列两行的两种放置方法(同行同列只能被一个元素占据)时,可以考虑只对一行两列的DP列的占用情况,对一列两行的DP行的占用情况。
我们最终合并时,可以算出当前剩余的单行数量分配给一行两列的元素,算出剩余单列数量分配给一列两行的元素,这就是一个组合数的合并了。\(f_ig_j{h-2i\choose j}{w-2j\choose i}\)
-
CF1237H 当特别明确每次操作奇/偶个数,需要留意相邻元素关系。
-
CF2127 F 利用期望和等价的思想,简化式子推导。
-
CF2133E 一棵树最多删 \(\lfloor\frac{n}{4}\rfloor\) 个点,剩下的每个连通块都是链,可以考虑自底向上时合并统计。
树上操作先考虑链。
-
CF2129D DP时注意各自变量的实际范围及复杂度。
-
CF2129E
虚假的莫队:每 \(\sqrt n\) 分块。
真实的莫队:按操作代价分块。
设移动端点 \(i\) 的代价为 \(w_i\),设 \(m=\sum w\)
考虑每个块的真实操作次数:设 \(a\) 为该块整体移动的代价和,精细分析一下其实是:
- \(l\) 在块内的询问个数乘以 \(a-w_l\),这是每次移动的最大值。
- 本块前面的块数乘以 \(a\)。不妨将其放缩为总块数。
那么真实的总代价应该是:总块数 * 总代价,加上每块询问数乘以块内代价的总和。
真实的分块策略应该是:
-
\(w_i\leftarrow \max(w_i,1)\)
-
设当前端点为 \(l\):
- \(w_l>\sqrt m\),独立成块。
- 找到最大的 \(r\),满足 \(w_l+w_{l+1}+\dots +w_r\le \sqrt m\),单独成块。
这样的总块数不超过 \(3\sqrt m\),且每块块内代价 \(\le\sqrt m\)(单独成块代价为零哦)。
我们常用来解决与图,代价与点度数相关的莫队问题——带权分块。
-
CF2131H
关于 \(\gcd\) 的问题,可以通过容斥等手段,化为带度数的图的问题(例如 \(\gcd=1\) 的点互相连边,可以用容斥 \(O(n\log n)\) 求得每个数的度数)
-
CF2127 F
精妙的利用期望和等效思想简化式子。
我们容易算出 \(F(n,m,k):\) 值域为 \([1,k]\),和为 \(m\),长度为 \(n\) 的序列个数,通过经典的枚举越界个数的容斥。复杂度 \(O(\frac{m}{k})\)。
枚举最大值 \(k\),考虑到一个序列的贡献可以表达为 \(k·cnt-\sum_{i}a_i[i=1\or a_{i-1}=k]\),那么拆贡献。
-
\(k·cnt\) 部分。
由于末位数字固定为最大值,算每个位置成为 \(k\) 的方案数则:
- \(i=n\):方案数为 \(F(n-1,m-k,k)\)。
- \(i\neq n\),方案数为 \(F(n-2,m-2k,k)\)。
-
\(i=1\or a_{i-1}=k\) 部分
- \(i=1\),由于在“值”这一方面,\(1\sim n-1\) 都是等效的,那么其期望权值就是 \(\frac{m-k}{n-1}\),因此贡献即为 \(\frac{m-k}{n-1}F(n-1,m-k,k)\)。
- \(1<i<n\),钦定 \(a_{i-1}\) 为 \(k\),则剩下的 \(n-2\) 个数在值上等效,期望权值为 \(\frac{m-2k}{n-2}\),方案数为 \(F(n-2,m-2k,k)\)。
- \(i=n\),权值为 \(k\),方案数为 \(F(n-2,m-2k,k)\)。
利用等效性和固定的和,直接求总和的平均数即为期望权值。
-
-
CF2128 F
这个确实很神。
首先遇到边取 \([l_i,r_i]\) 的任意值时,显然往往只会取 \(l_i,r_i\) 这两个值。
其次我们声明,只会有一条路径使用 \(l_i\),其余全部使用 \(r_i\)。(选定的不含 \(k\) 的最短路必然全 \(l\),其余全 \(r\) 能最大可能性地保障这条路)。
那么考虑选定的这条路 \(P:b_1=1,b_2\dots b_{m-1},b_m=n\)。
必然 \(\forall i<j,disR(b_i,k)+disR(b_j,k)>\sum_{x=i}^{j-1} wL(b_{x},b_{x+1})\) 。
那么直接进行 \(dp\),设 \(f_i\) 为点 \(i\) 作为当前端点时,所有转移到 \(i\) 仍然合法的路径的 \(\max \sum_{x=t}^{j-1}wL(b_x,b_{x+1})-disR(b_t,k)\) 的最小值。满足 \(b_j=i\)。
显然,点 \(i\) 合法当且仅当 \(disR(b_j,k)>f_i\)。同时考虑转移:
\(f_v=\min(f_v,\max(f_u+wL(u,v)),-disR(v,k))\)
显然使用优先队列,每次取出最小的 \(f_u\) 进行转移即可。
将限制条件刻画到路径上,利用 dijkstra 进行转移
-
ARC206C
给定数列 \(B\),连边 \(i\to B_i\),则对于任意 \([l,r]\) 的导出子图,\(l,r\) 连通。
当且仅当图是一颗基环树,且环是从大到小/从小到大遍历,且环外至多有两条链,分别是 \(1\to 2\to 3\to\dots,\dots\leftarrow n-3\leftarrow n-2\leftarrow n-1\leftarrow n\)。
在序列上体现为:存在一个 \(x,\forall y<x,B_y=y+1,\forall y>x,B_y=y-1,B_x\) 任意。
-
ABC424F,动态加入线段,判断是否与已有线段相交(不包含),则考虑维护 \(l\in [ql,qr]\) 的最大 \(r\),以及 \(r\in [ql,qr]\) 的最小 \(l\)。
-
ABC424G Hall 定理变式:
左部有 \(n\) 个男人,每个男人最多与 \(A_i\) 个女人结为朋友,右部有 \(m\) 个女人,每个女人需要与 \(B_i\) 个男人结为朋友,问是否存在朋友方案,使得每个女人都恰有 \(B_i\) 个男人与它为朋友。
根据 Hall 定理,将 \(B\) 降序后,对于每个 \(k\in [1,m]\),要求 \(\sum_{i=1}^n\min(A_i,k)\ge \sum_{j=1}^kB_j\)。
边权为 1,限制上界
-
ARC205E 插入与查询的平衡,对于二进制的 \(xor\),子集超集关系,当插入与查询复杂度不平衡的时候,考虑切割二进制位,前半在插入时遍历,后半在查询时遍历。
-
becoder contest 6557 T4
由 \((0,0)\) 走到 \((n,n)\),经过线段 \((0\sim w_k,k)\) 等价于经过线段 \((w_k,k\sim n)\)
这样可以将竖直线段化为水平,则可以将类竖直和水平的贡献统一为水平贡献。
-
becoder contest 6543 T4
写代码的时候慎用 continue,你不知道你会跳过什么奇怪代码
区分点双边双该用谁时,仔细讨论 \(\infty\) 这张图该不该分开。
-
becoder contest 6517
处理交换后的逆序对关系,有两个常见思路:
-
对于每个 \(i<j\),维护 \([a_i<a_j]\) 是否成立/成立的概率/方案数等
-
对于每个 \(i<j\),考虑其最初的出现位置 \(A,B\),那么其余位置全部等价为 \(C\)
则最终这两个数的位置对就只能为:
\[(A,B),(A,C),(B,A),(B,C),(C,A),(C,B),(C,C) \]那么将这七个状态挨个儿转移即可。
\(C\) 是指达到集合 \(C\) 中的每个位置等概率,且我们知道 \(C\) 里的位置与 \(A,B\) 大小关系的分布以算贡献。
参考 P4223。
-
-
P8350 同时对 \(2\) 进制和 \(3\) 进制做出限制,则考虑以 \(3\) 进制转移,暴力维护当前二进制,同时对于每个三进制,维护最高有效位二进制及其以下位即可,可以将复杂度开根号。
根号分治,前 \(3^{\frac{m}{2}}\) 至多延伸这么多状态,后面 \(3^{\frac{m}{2}}\) 状态总数是 \(O(3^{\frac{m}{2}})\) 的可记忆化。
从高位到低位如何处理进位问题?设一个状态表示钦定下一位是否进位即可。
-
becoder contest 6502
重构计算答案。若当前只需要 \([1,\frac{n}{ans}]\) 的信息足以,那么当 \(ans\) 变化时重构整个数据结构,则总重构量为 \(O(n\log n)\)。这样可以避免对多余信息的维护。
-
becoder contest 6460
对于序列 \(A\),选出一个子序列 \(b_1\sim b_m\),定义其得分为 \(\sum A_{b_i}(-1)^i\)。
则最大得分为:\(A\) 的差分数组正数之和。
交替加减——差分转化区间和。
-
2025.10.4 AT_cf17_final_j Bruvoka 每个连通块只能保留一条边,保留更多是错的
-
ARC144E 对于一张图 G, $1\to n $ 的所有路径长度相同的充要条件是删掉不能从 \(1\) 到达以及不能到达 \(n\) 的无效点后,所有的 \(\forall (u,v,w)\),都满足 \(d_v-d_u=w\),更强一些,所有路径长度都是 \(g\) 的倍数的充要条件是存在序列 \(d\),满足 \(\forall (u,v,w),d_v-d_u\equiv w(\bmod g)\)
-
CF1550F 对于绝对值中的二元关系处理,类似 \(||x-y|-d|\) 此类,可以选择将 \(x\) 拆为 \(x-d,x+d\) 这两个点分别与 \(y\) 求距离。更多元可能需要扩展空间并 \(2^{cnt-1}\) 枚举。——可用于 Bruvoka 中边权含绝对值的情形
-
CF1550F 用 Bruvoka 建立最小生成树,再建立Kruskal重构树时,需要注意重构树的边必须要用原本的点编号,而不是Bruvoka建立过程中的并查集代表元编号:
ed.emplace_back(u,v,w)是对的,而ed.emplace_back(find(u),find(v),w)是错的,ed.emplace_back(col[u],col[v],w)也是错的。其核心本质是 Bruvoka 的建立过程与 Kruskal 有本质差异,Bruvoka 并没有类似Kruskal的根据边权递增保证连通性变化的性质。 -
CF1920F 射线法:判断一个点是否在一个闭合回路内部,从这个点向任意方向引一条射线,若不考虑相切,那么和回路的交点为奇数时这个点在回路内部,否则在外部。“点可以扩展为一个连通块”
-
平衡树有交并
-
CF 1981 F,支配点对算生成树边权
当边权形式形如 \(|a_i-a_j|\) 时,对于 \(a_i<a_j<a_k\) 两两有边,必然连接 \((i,j),(j,k)\),\((i,k)\) 被支配。
-
P13350 条件概率的运用:当条件不明确时,不妨利用条件概率转化。在钦定一些事件发生的基础上,算某件事情发生的概率,可以算钦定事件发生的概率,再将这个事件也钦定住,两个概率相除得解。
-
P12462
- 将树拆为 \(k\) 条不相交的路径权值和最大——以某个直径端点作为根转化为长链剖分。
- 求一个点集构成的虚树的前 \(k\) 大长链,可以将点集分为两个部分分别求前 \(k\) 大长链再 \(O(k)\) 合并求最新的前 \(k\) 大长链。相当于直径的扩展。
- 这样就具备了分治结构,可以预处理一部分结果后优化询问的计算。
- 满足 ST 表的可重复性。
-
P12602
特殊图上的代换消元解期望。
在本题中,满足 \(f_i\) 的所有出边有且只有一条指向 \(i+1\),其余都指向 \(\le i\) 的部分。
那么完全可以设 \(f_0=x\),根据线性变换可以直接得到 \(f_{i}=k_ix+b_i\),最后求出一个确定状态的 \(k,b\) 进行反解。
-
P7515 针对特殊结构解决既有 \(x+y\) 又有 \(x-y\) 的限制的差分约束问题。
\[\begin{matrix} x_1+y_1&-x_1+y_2&x_1+y_3&-x_1+y_4\dots \\ x_2-y_1&-x_2-y_2&x_2-y_3&-x_2-y_4\dots\\ x_3+y_1&-x_3+y_2&x_3+y_3&-x_3+y_4\dots\\ \dots&\dots&\dots&\dots \end{matrix} \]可以试试将奇数/偶数行 \(x\) 取反,奇数/偶数行 \(y\) 取反。
-
CF685E 针对第 \(i\) 条边作用时间是 \([t_i,+\infty)\) 的问题,可以设 \(f_{x,y}\) 表示 \(x,y\) 首次连通时间,按 \(t_i\) 从大到小转移,每次只需要更新端点与其他点一共 \(O(n)\) 个状态。
-
开大额数组(ke6.1e7,1e8) 千万注意不要看错0
-
CF1896D 一个仅有1和2的数组,存在和为S的子区间就存在和为S-2的子区间。
-
P5999 连续段DP不仅可以在合并的时候选两段出来合并,也可以选择在新开一段的时候钦定段之间的顺序,插入已有顺序中去,合并时只需要选一个段之间的空合并即可。在处理合并/插入有特殊要求的问题适当转化
-
Gym105949 L \(\max(|a-b|,|a-c|,|b-c|)=\frac{|a-b|+|a-c|+|b-c|}{2}\)。绝对值符号可考虑向点距离转化,最值可与绝对值互相转化,与之类似的还有 \(|x_1-x_2|+|y_1-y_2|=\max(|(x_1+y_1)-(x_2+y_2)|,|(x_1-y_1)-(x_2-y_2)|)\)
-
\(k\) 维曼哈顿可以转 \(2^{k-1}\) 切比雪夫。
考虑 \(k\) 维两个坐标 \(\overline{a},\overline{b}\),有:
\(\sum_{i=1}^k|a_i-b_i|=\max_{i=0}^{2^k}\) 暴力大小关系枚举计算后的结果。而切比雪夫里的绝对值可以去掉一重枚举。
因此往往高维是曼哈顿转切比雪夫。这和暴力枚举每个绝对值式正负无甚区别 -
Qoj9406 \(s_i+s_j\le s_k\implies s_i<s_k,s_j<s_k\)。
-
ABC428F 处理编号连续的一段区间平移的问题,不妨考虑维护相邻区间左右端点的偏移量,将区间修改转化为单点。
-
CF1558F 在一些排序算法里,考虑依据断点转化为01序列的排序,需要的关键性质是当 \(\forall k\),\([p_i\le k]=[i\le k]\) 达成后会一直成立,那么排好序的最终时刻就是每个断点形成的时刻的最大值。
-
CF1556G 二进制的结构与 \([0,2^n-1]\) 的线段树很相似,不妨往这上面考虑,且 \(popcount(i\oplus j)=1\) 等价于 \(i,j\) 这两个叶子在线段树上往上走,在最后一步从左右儿子到lca之前,走的路径相同(当前点是父亲的哪个儿子相同)
-
P8511 对一棵树中每个 \(x\) 求最大的 \(a_p\oplus a_q\) 满足 \(p,q\) 都在子树外,那么找到全局最大的 \(a_p\oplus a_q\),对于 \(x\) 不是 \(p\) 或 \(q\) 祖先时答案相同,是的时候,可以拆为两条链,解决一条链只需要从上往下在“子树外集合”增加点即可,总复杂度 \(O(n\log V)\)。不妨记录其为 \(out_i\),在 P6072 中,求 \(\max_i(in_i+out_i)\),可以考虑到 \(out\) 取最值的 \(i\),其父亲如果 \(out\) 也取最值则 \(in_{fa}\ge in_i\),因此取出链删掉,只会取剩下的森林里每整棵树支配答案。而这条链上的 \(out\) 自顶向下好求,自底向上 \(in\) 好求。
-
P13536 等式可以联想图论建模 例如 \(i-h_i,i+h_i\) 之间可以连一条编号为 \(i\) 的边。
\[ \begin{cases} k-h_k&=i+h_i\\ j+h_j&=k+h_k\\ i-h_i&=j-h_j\\ \end{cases} \]这样的等式,可以表述为在 \((i-h_i,i+h_i)\) 这样的边之后的三元环计数。显然不会有重边。
-
P9675 给定若干直线,求在 \(x\) 取某个范围内所有整数时的最值和
- 方法1:\(O(n^2)\) 求出每个线段的最优范围区间并计算答案,但这里需要注意等号,实际上比较难受。
- 方法2:数据不强的时候,其实最优解段数不多,因此考虑直接分段,求出 \(f(x),f(x+1)\) 后二分这一段的终点 \(y\),它们的函数值构成等差数列,然后算这一段的答案并跳入下一段。
- 方法3:半平面交求凸包
-
P9675 无向图 \(s\to t\) 经过 \(i\) 条边的最短路,当 \(i\ge 4n\) 时,必然存在一条边 \((u,v)\),先走最短路到 \(u\) ,再反复走这条边,凑好步数后走 \(v\to t\)。因此该问题可以转化为一条直线(注意奇偶性)
-
agc039b
- 曼哈顿距离的限定转化为切比雪夫。
- 一个矩阵,每个点与曼哈顿距离或切比雪夫距离为 \(d\) 的点颜色不同,可以用不超过 \(4\) 个颜色染色。具体地,切比雪夫距离里,将点染色为 \(2(\lfloor\frac{x}{d}\rfloor\bmod 2)+(\lfloor\frac{y}{2}\rfloor\bmod 2)\) 。
-
CF1499 G,可以用带权并查集维护动态加边的欧拉回路——一个环成型后方案不会变动,因此将每个边视作点建立并查集。并记录链头。
当加入一条边时:
- 两个点都不是链头:新开一条链
- 有一个点是链头,更新链头到另一个点上
- 两个点都是链头,将其合并为一个环(清除链头标记)。
可以利用带权并查集维护方案(合并链时,可能需要反转链的颜色)。
-
CF1781G。小规模暴力,大规模找规律,并将大的非法情况转化为小的可暴力的情况。
-
CF1583F。有一个有向完全图,\(i<j\) 则有边 \(i\to j\),若限定路径长度 \(\ge k\) 时,要求至少有两种颜色,可以考虑分层图思想,建立 \(k\) 叉树,也就是边 \(i\to j\) 的边权 \(f_{i,j}=f_{{\lfloor\frac{i}{k}\rfloor},{\lfloor\frac{j}{k}\rfloor}}\)。
-
gym104901F 处理复杂序列DP转移/复杂答案统计(涉及区间等)时(从前往后),可以考虑CDQ分治计算,CDQ 一个很强的地方是可以将 可合并的序列信息转化为两个数的合并(提前合并中点两侧后前缀信息),从而大大简化题目。
-
完全图MST 只有两个常见思路:一个是通过性质证明只需要保留一部分边(通常线性或者单log,找支配关系),一个是用 Bruvoka
-
agc039b
- 曼哈顿距离的限定转化为切比雪夫。
- 一个矩阵,每个点与曼哈顿距离或切比雪夫距离为 \(d\) 的点颜色不同,可以用不超过 \(4\) 个颜色染色。具体地,切比雪夫距离里,将点染色为 \(2(\lfloor\frac{x}{d}\rfloor\bmod 2)+(\lfloor\frac{y}{2}\rfloor\bmod 2)\) 。
-
CF1499 G,可以用带权并查集维护动态加边的欧拉回路——一个环成型后方案不会变动,因此将每个边视作点建立并查集。并记录链头。
当加入一条边时:
- 两个点都不是链头:新开一条链
- 有一个点是链头,更新链头到另一个点上
- 两个点都是链头,将其合并为一个环(清除链头标记)。
可以利用带权并查集维护方案(合并链时,可能需要反转链的颜色)。
-
CF1781G。小规模暴力,大规模找规律,并将大的非法情况转化为小的可暴力的情况。
-
CF1583F。有一个有向完全图,\(i<j\) 则有边 \(i\to j\),若限定路径长度 \(\ge k\) 时,要求至少有两种颜色,可以考虑分层图思想,建立 \(k\) 叉树,也就是边 \(i\to j\) 的边权 \(f_{i,j}=f_{{\lfloor\frac{i}{k}\rfloor},{\lfloor\frac{j}{k}\rfloor}}\)。
-
gym104901F 处理复杂序列DP转移/复杂答案统计(涉及区间等)时(从前往后),可以考虑CDQ分治计算,CDQ 一个很强的地方是可以将 可合并的序列信息转化为两个数的合并(提前合并中点两侧后前缀信息),从而大大简化题目。
-
完全图MST 只有两个常见思路:一个是通过性质证明只需要保留一部分边(通常线性或者单log,找支配关系),一个是用 Bruvoka
-
\(\lfloor \log x\rfloor+1=\lceil\log (x+1)\rceil\)
-
agc097 B 交换两个0的个数与1的个数都相同的子区间,原序列逆序对数(10对)不会发生改变。
-
处理复杂的DP转移,可以考虑在转移内层再维护一个DP进行辅助转移。becoder contest 6666
-
在DAG上类行走问题的转移,不妨将其转换为矩阵乘法,那么“停留”可以描述为自环,同时不会破坏三角矩阵的性质 becoder contest 6643
-
分治可以处理出不具有可减性背包问题的,去掉每个元素后的背包状态。
处理办法是:void sol(int l,int r,int dp[]){ if(l==r){ans=dp;return ;} int tmp[]=dp[],mid=l+r>>1; add(l,mid,dp);sol(mid+1,r,dp); dp=tmp;add(mid+1,r);sol(l,mid,dp); } ``` -
ARC189A 式 \(f_0=1,f_i=\sum {i-1\choose j}f_jf_{i-1-j}\) 的解为 \(f_i=(2i-1)f_{i-1}\),其一个可能的组合意义是 \(n\) 个叶子的满二叉树(要么没儿子要么两个儿子)个数(考虑 \(n\) 个叶子时,有 \(2n-1\) 个节点,任选一个节点进行“扩展一个儿子”到 \(n+1\) 个叶子的方案)。
-
\(n\) 个点组成的无向环方案数为 \(\frac{(n-1)!}{2}\),特别的 \(n=2\) 时方案数为 \(1\)。
-
CF1874F 两个有交(非包含)区间 \([l_1,r_1],[l_2,r_2]\),若各自满足 \([l,r]\) 内数字是 \([l,r]\) 的排列,则将两区间拆出相交部分后的三个区间都满足——可用于容斥时的抵消——转化为有限制的区间全部包含或相离——树形结构——区间DP
-
ABC288EX——利用容斥在不更改序列xor和的情况下,将任意取容斥到元素互不相同
求出 \(f_i\) 为长度为 \(i\) 的满足题目 xor 限制的序列个数。这里不考虑元素之间的限制—— \(dp_{j,k}\) 填完二进制的前 \(j\) 位,现在有 \(k\) 个数字顶着上界的方案数。
从中容斥出 \(g_i\) 表示长度为 \(i\) 且元素之间互不相同的序列个数。
枚举 \(f_{len}\) 中含有 \(i\) 种元素出现奇数次,总出现次数为 \(j\),剩下 \(len-j\) 个元素为 \(k\) 种偶数。
可以求出 \(odd_{i,j},eve_{i,j}\) 分别表示将 \(i\) 个数分为 \(j\) 个大小为奇数/偶数的集合的方案数。
那么可以用 \(f_{i}\) 借助这些系数容斥 \(f_{len}\)。
-
QOJ6608 将区间 \([l,r]\) 中值为 \(x\) 的元素改为 \(x+1\),可以考虑主席树,版本 \(x\) 维护 \(\ge x\) 的元素信息,则相当于是版本 \(x\) 的区间 \([l,r]\) 复制到版本 \(x+1\) 的 \([l,r]\)。
-
写 \({n\choose 4}+s{n\choose 2}\) 的时候,不要写成 \((s+(n-3)(n-2)/12)(n-1)n/2\),会因为精度取整在 \((n-3)(n-2)/12\) 的时候爆掉
-
arc165e “从所有可操作的点里随机选一个进行操作”重复下去直到没有点能操作,这个等效于枚举所有点的操作顺序(一个全排列 \(p\)),然后按排列 \(p\) 的顺序操作点,若这个点不能操作就跳过,这与原问题概率是等价的
-
2025.11.13 CQ 友谊赛 T3,CF1996G,动态(增删区间)求被至少一个区间包含的点的点权和,正难则反线段树维护每个点覆盖次数,求所有最小值的点权和。
-
2025.11.13 CQ 友谊赛 T4,在线处理每个数左右侧前 \(m\) 个比它大的元素,可以维护一个 vector 存下当前右侧还不足 \(m\) 个数比它大的元素集合,每次直接暴力扫描,则每扫描一对至少有一个数字的次数-1,均摊 \(O(nm)\)
-
CF765G 给出质数 \(p_1\sim p_m\),在 \(N=\prod_{i=1}^m p_i\),\([0,N-1]\) 的每个数字 \(x\) 唯一对应一个有序序列 \(a_i=x\bmod p_i\),或者说这将所有数字划分为了 \(N\) 的同余类。
-
P14457 给定序列 \(b_i\in [0,n-1]\),找到 \([0,n-1]\) 的排列 \(p\) 满足 \(p_i\& b_i=b_i\)——建立网络流模型,\(i+n\to b_i\),容量 \(1\),对于每个 \(x\),将其多出一个二进制位的数字连边,容量无穷,然后 \(s\to i+n,x\to t\) 容量都是 \(1\)。\(O(n\log n)\) 的网络流,跑得很快。
-
P14449
给出森林,线性维护每个 \(r\),最小的 \(l\) 满足 \([l,r]\) 是一个毛毛虫森林。
等价于不存在一个点满足相邻度数 \(\ge 2\) 的点不超过 \(2\) 个。维护每个点的度数 \(d\),邻接点度数 \(\ge 2\) 的点的个数 \(c\) 以及 \(c>2\) 的点个数 \(t\)。
只有在 \(d\) \(1\to 2,2\to 1\) 才会对邻接点的 \(c\) 有影响。
而此刻它的邻接点除了当前枚举的这个 \(l\) 或者 \(r\) 之外只有一个,因此可以记录邻接点的编号异或和直接求出邻接点。
- 静态(先全部加入后全部查询)查询若干线段在某个下标取值的最值——求凸包,然后二分。
-
二维二分其实可以做树套树上二分,求和可以放在外层调用内层求和,一般采用线段树套树状数组
-
处理出区间 \([L,R]\) 的质数,\(R-L\) 比较小,预处理 \(\sqrt R\) 的质因数,用 \((\sqrt R\log\log\sqrt R)\) 暴力筛掉 \([L,R]\) 内含其质因子的元素,最后剩下的(除掉后) \(>1\) 的就是解
-
基于值域预处理的快速gcd算法:P5435
对每个数字 \(x\in[1,V]\),预处理出 \(\lbrace a_i,b_i,c_i\rbrace\) 满足 \(a_i\le b_i\le c_i\),且满足 \(a,b,c\le \sqrt x\) 或者是质数。
存在一组 \(\lbrace a_i,b_i,c_i\rbrace\) 满足其为 \(\lbrace a_{\frac{i}{p}}\times p,b_{\frac{i}{p}},c_{\frac{i}{p}}\rbrace\) 其中 \(p\) 为最小质因子。
可以欧拉筛预处理。
查询 \(gcd(x,y)\) 时,预处理 $\sqrt V $ 以内数字的两两 gcd,同时将 \(v_1=a_x,v_2=b_x,v_3=c_x\) 依次与 \(y\) 做运算,形如:
- \(v>\sqrt V\),直接判断 \(d=\gcd(v,y)\) 是 \(v\) 还是 \(1\),因为是质数。
- \(v\le \sqrt{V}\),直接求预处理好的 \(d=\gcd(v,y\bmod v)\)。
- 由此,再让 \(y\leftarrow \frac{y}{v}\)。
\(\gcd(x,y)=d_1d_2d_3\)
- ARC156F dinic 算法在退流时,由于按最短路增广,那么像 \(S\to u\to v\to T\) 的流量,如果想要 \(u,v\) 都没有任何流量流经,则需要走一条 \(S\to v\to u\to S\to …\to T\) 的路,这是不会发生的。
所以在遇到需要钦定某个 \(S\) 直接出发到达的点 \(u\) ,\(S\to u\) 这条边必须有流量,则可以预先找一组增广路让其有流量,那么这份流量一定不会退掉。
-
一张图如果满足任意导出子图都满足度数最小的点度数 \(\le k\),则 \(|E|\le |V|k\),同时这意味着可以将图进行 \(k+1\) 染色(也即给每个节点一个颜色,使得每条边的端点颜色不同)。
将点按度数从大到小排序,依次遍历,取第 \(i\) 个点的颜色是已经遍历过的相邻点颜色的 \(mex\) 即可。
-
CF1033 E
在一些特殊情境下(例如交互,或者查询一条边需要较大代价),判断图是否为二分图,可以先建立 DFS 树,再考察同色点内部是否存在边
-
P5287 我们知道 border 其实是 \(O(\log n)\) 段等差数列,所以在跳 $nxt $ 的时候其实还存在一个 \(O(\log n)\) 单次的跳法,可以适用于Trie树上每个点的 nxt 寻找。
我们知道,对于一段等差数列,除了最长的那个,剩下的段,它们的后一个字符都是相同的(循环节),因此用链表维护等差数列之间的联系,而每一段等差数列只需要考虑最长的次长。
也就是每个位置存下自己的 \(nxt\),以及到下一个等差数列的段头,每次遍历这个位置以及它的 \(nxt\),再跳到它的 \(nxt\) 的下一个等差数列的段头。
-
给定 \(n\) 个字符串,\(q\) 次询问,每次询问给出一个字符串,要求这 \(n\) 个字符串每个串在询问串的出现次数,只需要输出非 \(0\) 的即可。
设 \(L\) 为询问串以及初始串串长和,它们是一个量级。
我们声称 \(q\) 次询问总的出现过的模式串总和是 \(L^{\frac{4}{3}}\) 的,假定所有模式串不同。
设一个阈值 \(B\)。
-
对于长度 \(\le B\) 的串,显然它们的最多出现次数是 \(LB\),因为只有这么多的串。
-
对于长度 \(>B\) 的串,显然,如果有出现,那么说明询问串长度 \(\ge B\),至多有 \(\frac{L}{B}\) 个询问串和 \(\frac{L}{B}\) 个模式串,因此最多产生 \(\frac{L^2}{B^2}\) 的贡献。
\(\min (LB+\frac{L^2}{B^2})= 2L^{\frac{4}{3}}\)
-
-
CF 710 F
二进制分组重构思想。
适用于插入就必须重建的数据结构,例如AC自动机等。
其原理相当于将一个数据结构拆成 \(\log n\) 个。
设当前插入了 \(i\) 个,现在插入第 \(i+1\) 个。
首先为这个单点单开一个数据结构,然后重复:
若当前这些数据结构满足最小的两个大小相同,那就合并这两个数据结构(其实是直接重建一个新的)
用一个vector即可维护,只用了 \(O(\log n)\) 的额外代价就化解了插入不易的情况。
-
CF1408 F
每次能够让两个数变成一个相同的全新的数字,如何用尽量少的次数让所有数字相同?
考虑 \(n=2^k\) 的情况,递归解决,每次切半后 $(l,r),(l+1,r-1)\dots $ 配对即可。
一般情况:找到最大的 \(k\) 满足 \(2^k\le n\),解决 \([1,2^k],[n-2^k+1,n]\) 即可。
-
26.1.6 模拟赛T3 给定平面 \(n\) 个向量 \((x_i,y_i)\),\(S=\lbrace (x,y)|(x,y)=\sum_{t_i\in [0,1]}t_i(x_i,y_i)\rbrace\) 组成一个凸多边形,求法即为先做极角排序,然后斜率从小到大沿着一条一条向量移动,可以组建一个下凸壳,再走一遍可以拿出上凸壳。
-
P9070 矩阵内的每个元素允许与不同行的其他元素交换一次,保证 \(1\sim n\) 各自出现 \(n\) 次,则一定可以经过交换将每一行变成一个排列,具体构造方案是:考虑因为只能与不同行的交换,于是跑 \(n\) 次匹配,使得重排每一行的顺序让每一列变成一个排列(其实是求一个编号顺序),然后将矩阵转置回去即可。
-
\[\sum_{i}[L_i\le r\& R_i\ge l]=\sum_i[R_i\ge l]-\sum_{i}[L_i>r\& R_i\ge l]=\sum_i[R_i\ge l]-\sum_{i}[L_i>r] \]
这东西可以 \(O(1)\) 查询。
-
P9479 一棵树满足 \(\forall u,v,LCA(u,v)\le \max(u,v)+k\),充要条件是 \(\forall i,[1,i]\) 的虚树只用了 \([1,i+k]\) 之内的点
-
P10107 查询树上某个数子树内深度一定范围内的信息,可以考虑维护 \(s_u:\forall v:dfn_v\le dfn_u+sz_u-1,d_v\ge d_u\) 的信息,然后再维护 \(down_{u,i}\) 表示深度为 \(d_u+2^{i}\) 的 \(dfn\le dfn_u+sz_u-1\) 的 \(dfn\) 最大的点,再对于每个点维护同一深度的 \(dfn\) 前驱,那么可以 \(O(\log n)\) 找到向下深度为 \(l,r\) 的点做差分即可知道这些信息。
-
给定一棵树,有 \(k\) 个人从根开始行走,每个人每个时刻可以瞬移到一个被任意一个人访问过的节点,然后往外走一步,问最早遍历完整颗树的时间:设 \(cnt_i=\sum[d_x\le i],ans=\max_{1\le i\le maxdepth}\lbrace i+\lceil\frac{n-cnt_i}{k}\rceil\rbrace\)。P3571,可以看作点 \((i,n-cnt_i)\) 求上凸壳可以解决对于任意 \(k\) 的查询
-
$N\times M $ 的矩阵,满足每个数字 \(i\in[1,N]\) 都出现了 \(M\) 次,那么一定可以通过重排每一行使得每一列都是 \(1\sim n\) 的排列。具体地每次跑一个完美匹配即可,一定有解
-
P11103 & P9528
根据 Hall 定理,\(maxmatch=|V|-\max_{S\subseteq V}\lbrace |S|-|N(S)|\rbrace\)
而在这类题目中,左右部点是区间覆盖关系,也就是:- \(S\) 代表区间时,一定可以拆分为若干不交的 \([l_i,r_i]\) 而 \(N(S)\) 就是这些区间内的点个数。
- \(S\) 代表点时,\(N(S)\) 一定可以拆分为若干不交区间 \([l_i,r_i]\)
因此可以使用 \(dp\) 表达选取过程:
-
\(f_{i}=\max(f_{i-1},\max_{j}f_j+w(j+1,i))\),那么可以使用数据结构 DP 出这个最优解,而 \(w(l,r)\) 就是选一段这样的区间的 \(|S|-|N(S)|\) 的结果。
在 P11103 中,涉及了部分区间的变化,那么同样可以借助前缀后缀DP,用数据结构辅助计算贡献。
一般的区间对点即为这样处理,但还有点对点,匹配规则一致的情况:一个位于数轴上点 \(x\) 的左部点与位于 \([x-L,x+L]\) 的右部点有边,求最大匹配。
仍然可以将左部点的选取看作选取若干区间 \([l_i,r_i]\) 那么对应的右部点就是 \([l_i-L,r_i+L]\),通过两个前缀和可以直接写出贡献。
问题再次变为选取若干不交区间的最大权值。不过在这个问题中,一个区间的权值是可差分的,那么可以直接设计 \(f_{i,0/1}\) 表示 \([1,i]\) 现在已经选了最后一个区间的左端点/还没有开始选最后一个区间,做线性 \(DP\) 即可。
特别的,由于求解的是 \(max\),那么在最优方案中 \([l_i-L,r_i+L]\) 是不交的。可以利用这个性质将转移搬到数据结构上。
-
P10685
左部点向右部点区间连边的匹配,经典贪心是从小到大枚举右部点,然后将尚未匹配的且能匹配的且 \(r_i\) 限制最小的匹配。
本题中是左部点向右部点区间连边 \([l_i,r_i],[l_i,r_i+1]\dots [l_i,r_i+k_i]\) 这 \(k_i+1\) 个点,对应线段树上就是区间加,匹配的话就是线段树二分,单点修改,区间置为0。
-
CF1336E2,对于一个线性基 \(B\),设一个形式幂级数 \(F(x)=\sum x_i[i\in span(B)]\),则 \(FWT[F(x)]\) 只有在 \(i\in span(B^{\perp})\) 的项有系数 \(2^{|B|}\),其余地方系数都是 \(0\)。可以借此实现关于 \(B\) 的基数转到 \(B^{\perp}\) 的计数上
-
格雷码与线性基:
经典问题:给定数集 \(S=\lbrace a_1,a_2\dots a_n\rbrace\),这里保证 \(a_i\in [0,2^m)\) ,要求你给出一个长为 \(2^m\) 的构造 \(b_{0}\sim b_{2^m-1}\),满足 \([0,2^m)\) 每个数字最多出现一次,且满足 \(b_{i}\oplus b_{i+1}\in S\)。
建立线性基,只保留 \(S\) 中能够成功插入线性基的 \(m\) 个元素,如不足则无解。
建立 \([0,2^m)\) 的格雷码,对于每一位为 \(1\),这个数字就异或上线性基这一位的基。
那么我们就表达出了线性基的所有组合方式,也就是 \(2^m\) 个数字,同时满足了相邻两个数字异或必然是一个基,也就是 \(S\) 中的元素。
-
给定序列 \(a_1,a_2\dots a_n\),动态判断数字 \(x\) 能否在 \(a\) 中选取偶数个数字得到。
设 \(b_i=a_i\oplus a_{i+1}\),则 \(b\) 的线性基可以表达选取偶数个 \(a\) 中元素的所有信息。ARC173E
-
最小生成树计数:对于每个 \(w\),只考虑边权 $\le w $ 的边,连通状况是确定的,那么问题相当于从小到大枚举边权 \(w\),对于现在的连通性缩点,然后加入所有边权为 \(w\) 的边,每个连通块做矩阵树定理。
-- ABC228G ARC193B 都在说明一个道理:做计数DP,当每一步的组合对象很少时,若想要去重,不妨将状态设为这一步有哪些组合对象仍然可能合法,换言之看作DFA的转移就是从起点开始表达出当前这个串的可能的终点集合。
-
给定一个n* m的网格,其中每个格子是黑色或者白色,如何判定是否存在铺设1* 2或者2* 1瓷砖的方案,使得瓷砖恰好能覆盖所有白色格子一次,经典做法是看作二分图跑完美匹配。
-
AtCoder-mujin_pc_2018_h DP of dp 中,如果有了想法却发现理论状态数很大,不妨搜一下有用状态数
-
P8352 设点权为 \(w_u\),则树上最大独立集 dp 时:设 \(g_u=f_{u,1}-f_{u,0}\),则:
\(g_u=w_u-\sum f_{v,1}-\max(f_{v,1},f_{v,0})=w_u-\sum\max(0,g_v)\),因此 \(g_u\le w_u\),且 \(g_u<0\) 对后续转移无用。 -
Q:已知 \(nxt_i:[i,n]\) 的后缀里 \(p_i\) 的后继,如何还原排列 \(p\),用平衡树是容易的,有更简单的做法吗
-
A:连边 \(nxt_i\to i\),不存在 \(nxt\) 设为 \(n+1\),以 \(n+1\) 为根,儿子编号从小到大遍历,它的 dfs 序就对应了排列 \(p\) 的排名(从大到小)。
-
P13693 极小 \(mex\) 区间个数不超过 \(2n\)。
考虑所有 \(a_l>a_r\) 的区间,假设存在一个极小 \(mex\) 区间 \([l,r]\) 满足 \(a_l>a_r\),则对于所有的 \(a_l>a_{r'},r'\neq r\),都可以论证 \([l,r']\) 不是极小 \(mex\) 区间:\(l<r'<r\implies mex[l,r']\le r\) 因此删掉 \(l\) 不会有问题,而 \(r'>r\) 的情况,\(mex[l,r]>a_l>a_{r'}\) 因此 \(a_{r'}\) 已经出现于 \([l,r]\),是无用的位置。反过来论证 \(l\) 对于 \(r\) 是由于的。
因此,可以使用线段树,先维护出 \([1,r]\) 的 mex,可以 \(O(n)\) 倒着算,然后 \(l:1\to n\),每次相当于找到 \(r<nxt_l\) 的,且 \(mex>a_l\) 的覆盖为 \(a_l\),由于 \(mex\) 单调性这肯定是一段区间,找出来 \([r_1,r_2]\) 进行覆盖,那么 \([l,r_1]\) 就是一个要求的区间。
由此观之,一个序列的所有子区间的 \(mex\) 只会由 \(O(n)\) 个量决定。
那么解决此题:定 \(mex\ge k\) 的情况下,从 \(l\) 开始往后跳多少次可以跳过 \(r\),就可以将 \(mex=k\) 的所有极小区间拿出来,做倍增即可。
-
一个 DAG 从 \(1\) 出发可以到达所有点(满足 \(1\sim n\) 为一个拓扑序),等价于 \([2,n]\) 每个点都有入度。
-
点分治可以很方便计算 \(q\) 个要求 \((v_i,d_i)\):求每个点 \(x\) 满足多少个 \(dis(x,v_i)=d_i\) 的限制的问题。可以做到 \(O((n+q)\log n)\)。P11194
-
给定下三角矩阵(将区间表达为矩阵),满足性质:\(\forall 1\le a\le b\le c\le d\le n\),\((a,d)\) 是小于 \((b,c)\) 的。求解其第 \(k\) 大是谁。
那么,不妨将 \((l,r),l\le r\) 写成一个下三角矩阵,考虑对于一个随机区间 \((x,y)\),如何确定它的排名。
从右上角开始向下向左游走,由于每一列从上往下递增,每一行从左往右递增,因此比较当前点与 \((x,y)\) 的大小关系,可以确定往下走还是往左走。
这样就能在 \(O(n)\) 次走出一条分界线,并算出其排名。
那么,我们取现在还活着的每一列的中位数出来,将这些中位数的中位数取出来(这一步不超过 \(O(n)\),根据序列的结论),作为这个选择的区间。
会有一半的列中位数大于一半的小于,那么无论我们选择扔下面的还是扔掉上面的,都能抛弃掉矩阵大概 1/4 的大小的一个角。
剩下的问题递归解决。
注意到在两层递归中,我们基本上会选择两个分点,它们会将初始局面与一个带状做取舍,根据数学证明,新区域的边长和是原本边长和的大约 $\frac{3}{4} $ 倍.
因此只需要比较 \(O(n)\) 次。用普通的二分法需要比较 \(O(n\log n)\)
- 给定下三角矩阵(将区间表达为矩阵),满足性质:\(\forall 1\le a\le b\le c\le d\le n\),\((a,d)\) 是小于 \((b,c)\) 的。求解其第 \(k\) 大是谁。
那么,不妨将 \((l,r),l\le r\) 写成一个下三角矩阵,考虑对于一个随机区间 \((x,y)\),如何确定它的排名。
从右上角开始向下向左游走,由于每一列从上往下递增,每一行从左往右递增,因此比较当前点与 \((x,y)\) 的大小关系,可以确定往下走还是往左走。
这样就能在 \(O(n)\) 次走出一条分界线,并算出其排名。
那么,我们取现在还活着的每一列的中位数出来,将这些中位数的中位数取出来(这一步不超过 \(O(n)\),根据序列的结论),作为这个选择的区间。
会有一半的列中位数大于一半的小于,那么无论我们选择扔下面的还是扔掉上面的,都能抛弃掉矩阵大概 1/4 的大小的一个角。
剩下的问题递归解决。
注意到在两层递归中,我们基本上会选择两个分点,它们会将初始局面与一个带状做取舍,根据数学证明,新区域的边长和是原本边长和的大约 $\frac{3}{4} $ 倍.
因此只需要比较 \(O(n)\) 次。


浙公网安备 33010602011771号