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 卷] 树 整体异或、求 ( ext{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|-maxlimits_{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] 劈配
最大权闭合子图:正权点权值和 (-) 最小割。
最大密度子图:二分 (gleqslantfrac{|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 ightarrow y,y^prime ightarrow x^prime)
不能同时存在:(x ightarrow y^prime,y ightarrow x^prime) 必须同时存在:(x ightarrow y,x^prime ightarrow y^prime)
至少存在一个:(x^prime ightarrow y,y^prime ightarrow x) 至多存在一个:(x ightarrow y^prime,y ightarrow x^prime)
不能存在:(x ightarrow x^prime) 必须存在:(x^prime ightarrow 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=sumlimits_{i=1}^na_ifrac{M}{m_i}t_i),其中 (M=prodlimits^n_{i=1}m_i,frac{M}{m_i}t_iequiv 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) 引理:
(Pacute olya) 定理:
筛法
博弈论
反演
莫比乌斯反演:
二项式反演:
注意是钦定,不是至少至多。
单位根反演:
原根
若 (delta_p(g) = varphi(p)),则 (g) 为模 (p) 的一个原根。最小原根大小是 (O(p^{frac{1}{4}})) 的,用 (g^{frac{varphi(p)}{p_i}} ot equiv 1 pmod{p}) 检验暴力求即可。
二次剩余
字符串
border
(WPL):若 (i,j) 是字符串 (s) 的周期,且 (i+jleqslant |s|),则 (gcd(i,j)) 也是 (s) 的周期。
AC 自动机
要注意根为 (0)。
后缀自动机
若维护了一个节点的 ( ext{endpos}) 集合的最小位置,新建 (nq) 时,要从 (q) 继承。
广义后缀自动机暴力跳 (fa) 时打标记来保证正确性(每个串只有一次贡献)和复杂度((nsqrt n))。[SCOI2012] 喵星球上的点名