review
DP
动态 DP
❌模板
整体 DP
线段树合并时,当 \(x,y\) 其中一个没有儿子时,就打标记返回。[PKUWC2018] Minimax [ZJOI2019] Minimax搜索 [CEOI2019] Magic Tree
概率期望 DP
求期望时,可以试试对状态差分。
条件概率:\(P(A|B)=\frac{P(AB)}{P(B)} \Rightarrow E(A|B)=\frac{E(AB)}{P(B)}\)。
贝叶斯公式:\(P(A|B)=\frac{P(B|A)P(A)}{P(B)}\)。
计数转概率:[AGC030D] Inversion Sum
计数 DP
和区间有关的计数大部分都是先离散化转为左闭右开 \([\ )\) 后再处理。某位歌姬的故事 [APIO2016] 划艇
树形 DP
长链剖分:用 \(vector\) 实现。Dominant Indices [POI2014]HOT-Hotels [WC2010]重建计划
if(len[y]>=len[son[x]]) son[x]=y,len[x]=len[y]+1;
\(dfs\) 序优化背包:决策是否加入当前子树。
决策单调性
斜率优化
\(x\) 单调,\(k\) 单调,单调队列维护。
\(x\) 单调,\(k\) 不单调,凸包上二分。[SDOI2012] 任务安排
\(x\) 不单调,\(k\) 不单调,\(CDQ\) 分治或平衡树维护。[NOI2007] 货币兑换
用李超线段树来维护更方便。[CEOI2017] Building Bridges
树上点分治斜率优化。[NOI2014] 购票
凸优化
[八省联考2018] 林克卡特树 至多选 \(k\) 个:[CEOI2011] Hotel
注意考虑凸包上共线的情况,就是最后计算答案时不能用 \(DP\) 求出的个数 \(cnt\),要用给定的限制 \(k\)。
数据结构
线段树
维护单调栈:楼房重建 [HNOI/AHOI2018] 转盘 区间查询:实现 粉兔文章
李超线段树:模板:[CEOI2017] Building Bridges 线段树合并:CF932F Escape Through Leaf 线段:[HEOI2013] Segment
❌势能线段树
dsu on tree
处理静态子树询问。CF208E Blood Cousins CF741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths
LCT
维护子树和连通块:SP16580 QTREE7 - Query on a tree VII
\(access\) 染色:「雅礼集训 2017 Day7」事情的相似度
K-D Tree
重构:简单题 打标记:[Ynoi2008] rrusq 方方方的数据结构
注意是平衡树写法,节点上有信息。
01 Trie
整体加 \(1\):[省选联考 2020 A 卷] 树 整体异或、求 \(\text{mex}\):[清华集训2016] Alice 和 Bob 又在玩游戏 可持久化:[HEOI2013] ALO
图论
同余最短路
[国家集训队] 墨墨的等式 CF516E Drazil and His Happy Friends
最小环
\(Floyd\) 外层循环枚举到 \(k\) 时,用 \(dis_{i,j} + val_{i,k} + val_{k,j},i<k,j<k\) 更新答案,其中 \(dis\) 为最短路径长度,\(val\) 为边权。
二分图
最大匹配必须边:满流,且 \(x\) 和 \(y\) 在残量网络上属于不同的强连通分量。
最大匹配可行边:满流,或 \(x\) 和 \(y\) 在残量网络上属于同一个强连通分量。
最大匹配必须点:在残量网络上,以 \(S\) 为起点遍历流量为 \(1\) 的边,没有遍历到的匹配点为左部图的必须点,以 \(T\) 为起点遍历流量为 \(0\) 的边,没有遍历到的匹配点为右部图的必须点。(这里遍历的就是未满流边)
霍尔定理:最大匹配为 \(|X|-\max\limits_{S \subseteq X}\{|S|-|N(S)|\}\),其中 \(N(S)\) 是和 \(S\) 相连的点集。(再做几个相关题)
最小点覆盖 \(=\) 最大匹配 [USACO05JAN] Muddy Fields G
最小边覆盖 \(=\) \(n-\) 最大匹配
最大独立集 \(=n−\) 最大匹配 CF1404E Bricks
\(DAG\) 的最小路径点覆盖 \(=n−\) 拆点二分图最大匹配
\(Dilworth\) 定理:最长反链 \(=\) 最小可重链覆盖
网络流
注意流量为实数时的精度问题,不能用极大值减较小值,会舍掉精度。
最小割可行边:满流,在残量网络上不存在 \(x\) 到 \(y\) 的路径。(缩点后判断,等价于 \(x,y\) 属于不同的强连通分量)
最小割必须边:满流,是可行边,在残量网络上存在 \(S\) 到 \(x\) 和 \(y\) 到 \(T\) 的路径。(缩点后判断,等价于 \(x\) 和 \(S\) 属于同一个强连通分量,\(y\) 和 \(T\) 属于同一个强连通分量)
退流:要删掉边 \((x,y)\),\(x\) 到 \(S\) 跑最大流,\(T\) 到 \(y\) 跑最大流,总流量减去这两个最大流的较小值,然后就能直接删掉 \((x,y)\) 了。[SDOI2014] LIS 元旦老人与丛林 [八省联考2018] 劈配
最大权闭合子图:正权点权值和 \(-\) 最小割。
最大密度子图:二分 \(g\leqslant\frac{|E|}{|V|}\),得 \(|E|-|V|×g \geqslant0\),转化为最大权闭合子图。
❌上下界:有源汇转无源汇时记得加 \((T,S,0,inf)\)。求最小流时,加这条边前就跑一遍最大流,加了后再跑一遍最大流,这条边的流量就是最小流。
❌循环流
Tarjan
\(low_x\):在以点 \(x\) 为根的子树内的点通过非树边的一条边到达的 \(dfn\) 最小的节点 \(y\) 的 \(dfn\) 值,\(y\) 能到达 \(x\)。
强连通分量:\(dfn_x=low_x\),更新 \(low_x\) 时判 \(vis_x\)。
点双连通分量:\(dfn_x \leqslant low_y\)。
边双连通分量:\(dfn_x < low_y\),更新 \(low_x\) 时判 \(link\)。
圆方树
只有圆方边,圆点度数为去掉该点后形成的连通块个数,方点度数为点双大小。
处理仙人掌时两点一边间不再新建方点,即存在圆圆边。
差分约束
❌
如果我们有一些限制形如 \(x_a−x_b<=d\)
那么我们可以把它联系到最短路上,如果 \(b→a\) 有一条长度为 \(d\) 的边,那么必然有 \(x_a<=x_b+d\)
这样我们求最短路,可以得到 \(x_a\) 的最大值
为什么是小于等于号却是最大值呢,因为我们是从正无穷向下规约的
2-SAT
一个存在后另一个必须存在:\(x\rightarrow y,y^\prime\rightarrow x^\prime\)
不能同时存在:\(x\rightarrow y^\prime,y\rightarrow x^\prime\) 必须同时存在:\(x\rightarrow y,x^\prime\rightarrow y^\prime\)
至少存在一个:\(x^\prime\rightarrow y,y^\prime\rightarrow x\) 至多存在一个:\(x\rightarrow y^\prime,y\rightarrow x^\prime\)
不能存在:\(x\rightarrow x^\prime\) 必须存在:\(x^\prime\rightarrow x\)
选择缩点后编号较小的状态。要连逆否命题。
前缀优化建图:[PA2010] Riddle CF1215F Radio Stations CF1007D Ants CF587D Duff in Mafia
最小树形图
斯坦纳树
虚树
bool cmp(const int &a,const int &b)
{
return dfn[a]<dfn[b];
}
void build()
{
sort(s+1,s+tot+1,cmp);
for(int i=tot-1;i;--i) s[++tot]=lca(s[i],s[i+1]);
sort(s+1,s+tot+1,cmp),tot=unique(s+1,s+tot+1)-s-1;
for(int i=2;i<=tot;++i) fa[s[i]]=lca(s[i],s[i-1]);
}
注意清空的复杂度。
欧拉图
void dfs1(int x)// 无向图
{
for(int &i=head[x];i;i=e[i].nxt)
{
if(vis[i]) continue;
int l=i;
vis[i]=vis[i^1]=true,dfs1(e[i].to),p[++cnt]=l&1?-(l>>1):(l>>1);
}
}
void dfs2(int x)// 有向图
{
for(int &i=head[x];i;i=e[i].nxt)
{
if(vis[i]) continue;
int l=i;
vis[i]=true,dfs2(e[i].to),p[++cnt]=l;
}
}
Kruskal 重构树
for(int i=1;i<=m;++i)
{
int x=find(ed[i].x),y=find(ed[i].y);
if(x==y) continue;
val[++tot]=ed[i].v,add(tot,x),add(tot,y);
fa[x]=fa[y]=f[x][0]=f[y][0]=tot;
if(tot==2*n-1) break;
}
三元环
for(int i=1;i<=m;++i)
{
int x=ed[i].x,y=ed[i].y;
if(deg[x]>deg[y]||(deg[x]==deg[y]&&x>y)) swap(x,y);
add(x,y);
}
for(int x=1;x<=n;++x)
{
for(int i=head[x];i;i=e[i].nxt) vis[e[i].to]=x;
for(int i=head[x];i;i=e[i].nxt)
for(int j=head[e[i].to];j;j=e[j].nxt)
if(vis[e[j].to]==x)
ans++;
}
四元环:
bool cmp(int x,int y)
{
return deg[x]==deg[y]?x<y:deg[x]<deg[y];
}
for(int x=1;x<=n;++x)
{
int y,z;
for(int i=head[x];i;i=e[i].nxt)
if(cmp(x,y=e[i].to))
for(int j=head[y];j;j=e[j].nxt)
if(cmp(x,z=e[j].to))
cnt[x]+=vis[z],cnt[y]+=vis[z],cnt[z]+=vis[z]++;
for(int i=head[x];i;i=e[i].nxt)
if(cmp(x,y=e[i].to))
for(int j=head[y];j;j=e[j].nxt)
if(cmp(x,z=e[j].to))
cnt[y]+=--vis[z];
}
k 短路
哈密顿图
P3561
Prufer 序列
长为 \(n-2\),值域为 \([1,n]\),\(i\) 的出现次数为其对应的有标号无根树中 \(i\) 的度数减一。
\(k\) 个连通块,加 \(k-1\) 条边使图连通的方案数为 \(n^{k-2}\prod a_i\)。
数学
线性基
本质是消元,可以用来求解异或方程组。求第 \(k\) 小异或和时,将线性基的第 \(i\) 位消元为只有二进制中的第 \(i\) 位为 \(1\) 即可。实现
多项式
牛顿迭代:
类欧几里得算法
欧拉定理
中国剩余定理
\(crt\):解为 \(x=\sum\limits_{i=1}^na_i\frac{M}{m_i}t_i\),其中 \(M=\prod\limits^n_{i=1}m_i,\frac{M}{m_i}t_i\equiv 1 \pmod{m_i}\),即 \(t_i\) 为 \(\frac{M}{m_i}\) 在模 \(m_i\) 意义下的逆元。(注意计算 \(\frac{M}{m_i}t_i\) 时,不要对 \(m_i\) 取模)
\(excrt\):两两合并方程:
ll excrt()
{
ll ans=a[1],M=m[1];
for(int i=2;i<=n;++i)
{
ll g=exgcd(M,m[i]),tmp=((a[i]-ans)%m[i]+m[i])%m[i];
if(tmp%g!=0) return -1;
ans+=mul(x,tmp/g,m[i])*M,M*=m[i]/g,ans=(ans%M+M)%M;
}
return ans;
}
卢卡斯定理
扩展卢卡斯定理:
\(n\) 小,\(p\) 大,\(p\) 为合数时计算组合数的方法:预处理阶乘时不算 \(p\) 质因子的贡献,这样就有了逆元,计算组合数时再加上质因子的贡献。CF896D Nephren Runs a Cinema
取模技巧:[CEOI2004] Sweets [SDOI2013] 项链
BSGS
取 \(\sqrt p\) 时要上取整。要注意 \(exBSGS\) 解比较小的情况。
Pollard-Rho
置换群
\(Burnside\) 引理:
\(P\acute olya\) 定理:
筛法
博弈论
反演
莫比乌斯反演:
二项式反演:
注意是钦定,不是至少至多。
单位根反演:
原根
若 \(\delta_p(g) = \varphi(p)\),则 \(g\) 为模 \(p\) 的一个原根。最小原根大小是 \(O(p^{\frac{1}{4}})\) 的,用 \(g^{\frac{\varphi(p)}{p_i}} \not \equiv 1 \pmod{p}\) 检验暴力求即可。
二次剩余
字符串
border
\(WPL\):若 \(i,j\) 是字符串 \(s\) 的周期,且 \(i+j\leqslant |s|\),则 \(\gcd(i,j)\) 也是 \(s\) 的周期。
AC 自动机
要注意根为 \(0\)。
后缀自动机
若维护了一个节点的 \(\text{endpos}\) 集合的最小位置,新建 \(nq\) 时,要从 \(q\) 继承。
广义后缀自动机暴力跳 \(fa\) 时打标记来保证正确性(每个串只有一次贡献)和复杂度(\(n\sqrt n\))。[SCOI2012] 喵星球上的点名