一些小东西的总结
空间需要开多倍的算法
需特别注意题目中是否存在值域与其他数组不同的数组,要开多倍空间
- 无向图连边
- 线段树,可持久化线段树,线段树分裂,合并
- 可持久化平衡树
- 后缀自动机
- ST表第二维要开大一些,不能卡线开
- 离散化时记得计算值的数量
- 字!典!树!
关于max的注意事项
- 对inf取max的时候要将inf转化成long long 形式,使用const而非define可以很好的解决这个问题
K-D Tree的奇妙卡常技巧
- 顶层分块:将树拆成多个做
- 底层分块:包含点树较少时直接存起来
- (通用)随机剪枝:如果子树不可能合法就直接不再访问,为防止特殊构造可以随机顺序访问
前缀和
我对前后缀的理解不足1%
前后缀在大多数题目中与优化中都有涉及,但是仍旧存在一些特殊的优化情况,
这里不再记录普通优化,而是记录目前本人见过的特殊优化。
前后缀优化dp
类型1:相邻两段区间存在交集
代表题目:CF708E CF2204G
主要思想:
由于区间相交的要求可以认为是很严格的,区间[l,r]与区间[l',r']有交的条件是l<=r'且r>=l'。
这样,我们考虑使用总和减去不合法的,也就是r'<l与l'>r的部分。
这样我们就将dp的f[l][r]的转移的一维优化掉了,可以来达到降低时间复杂度的效果。
注:在部分情况中(实际上上面两道题都属于)左右两端不合法的区间的综合的权值是相同的,可以将前后缀不合法放到一起考虑。
前后缀考虑构造方案
例题:AT_arc129_d
其实差分也有类似的,但是和这个整个近乎相同,就不单独讨论了。
在这种类型的题目中,进行一次操作在与序列上可能极为抽象,但是放置到前缀和或者差分上就变得有规律可循了。
通过这种转化可以让我们更方便的想出题目。
前后缀维护波动范围
例题:糖果游戏
题目转化完之后的意思就是对于 $ A_i $ 令 \(x=min(max(0,x+A_i),m)\) ,从前往后做并不好做,考虑维护后缀波动的范围,如果后缀波动范围超过了 m ,那么前缀具体数值就没有作用了,只需要继续计算右子树即可,否则在继承右子树的前提下继续递归左子树,最后将答案确定在一个后缀,或是整个序列。
如果是整个序列,那么直接让他加上所有数值的和,在针对最小值与最大值进行调整(这里指的是找到不合法位置,然后再重新计算后缀,因为波动范围小于m,所以调整完之后一定合法)。
如果是一个后缀,首先判断最后是 m ,还是 0 ,这取决于后缀的和是正是负(这里解释一下,假如从k开始的后缀不合法,即最大后缀和和最小后缀和相差超过m,那么计算k开始的后缀和,如果是正的,说明无论这个数字填多少,后面始终会超过m,为了保证他不会即被最小值判断又被最大值判断,所以,不妨认为进行了前k次操作之后,他的结果是m。负数同理),判断之后按照上面的步骤模拟即可。
分块
不等长分块
例题:qoj8784
原理:在这类题目中,等长分块并不是很优秀。
可以通过前长后短或前短后长,或者干脆写一个dp来算出最有分块策略,以此符合题目要求。
平衡复杂度
例题:大!数!字!
原理:由于分块的存在,导致块内更新和整块更新前后缀或类似的东西复杂度都是 $ O(\sqrt n) $的,但是他的查询是可以做到将两部分拼起来达到 $ O(1) $ 的,因此可以用来平衡复杂度,将 $ O(n+n\sqrt{n}logn) $ 变成 $ O(n\sqrt{n}+n\sqrt{n}) $
dp
贪心优化背包
在刚开始学习的时候,我们就知道,贪心去选择在背包问题中是错误的,但是当满足一定条件后,背包就可以被贪心优化了
这有如下几种可能:
1.在V足够大(这里的足够大指大于最大重量的平方)的时候,我们可以优先选择性价比最高的,再对其进行调整。
2.在多重背包中,\(w_i,v_i,cnt_i,c_i\)分别表示i物品的重量,价值,最多选择数量,已经选择数量,如果存在 $ \frac{v_i}{w_i}\ge\frac{v_j}{w_j} $ 且 $ c_i\le cnt_i-v_j,c_j\ge v_i $,那么我们可以调整,将 $ v_i $ 个 $ j $ 物品,变成 $ v_j $ 个 $ i $ 物品,这样总价值不变,但是总重量减少。
根号分治背包
物品重量 1-n 背包大小 1-n 01背包,怎么求方案数
考虑根号分治,我们最多只有根号个物品,考虑将图横过来,维护<=i的数的数量当做背包权值。
这样数值是递减且差值<=1的,直接背包分层做即可。
正难则反
倒叙进行操作
在对于一些题目要求维护删除/插入操作时,可以考虑倒叙维护插入/删除操作,可能会使题目变得更加方便计算。
状态转换
P4484,如果你有多维,枚举其中一维不好做,可以考虑枚举别的维度
最小生成树
对于Kruskal重构树来说,如果每颗子树内只需要一个节点就可以代表整个子树,那么可以将图合并为一条链
二分图
二分图博弈
1.对于二分图博弈,先手如果率先落入最大匹配的点x中,那么后手只需要选择与x匹配的点y走即可,走到最后先手必败;
2.如果是完全匹配,那么先手无论落子何处,均率先落入最大匹配点,先手必败;
3.如果不是完全匹配,先手选择非最大匹配点x落子,那么后手无论落子何处,都是最大匹配中的某点y, 因为如果y不是最大匹配的点, 则x到y形成增广路,最大匹配的边数还可以加1,导致矛盾;进而, 后手率先落入最大匹配的点中,先手有必胜策略;
没有完美匹配的二分图性质-唯一代表元
对于所有没有完美匹配的二分图,代表元可以设置为S,使得|S|-N(S)是最大的,如果相同,则|S|最小。
可以证明这里的S是唯一的。

该性质可以用于计数或者容斥
P13693(mex性质)
这道题主要有两个性质比较奇特:
1.最小mex区间的数量只有2n个
2.如何使用线段树维护最小mex区间,不难发现右端点不变左端点右移时mex单调不增,直接维护相同连续段找到右边第一个更改位置即可。
对于园/直线基于另一个园做反演
1.定义:设基准园圆心为\(O\),反演半径为\(r\)
则对于一点\(A\),其反演点\(A'\)满足\(A\),\(A'\),\(O\)三点共线且\(|OA|*|OA'|=r^2\)。
2.性质:
对于一个圆做反演变换:
若O位于圆弧上,则结果为一条直线,否则结果为另一个园。
对于一个直线做反演变换:
若O不位于直线上,则结果为园,否则结果依旧为这条直线。
若两园/直线原本相切,则反演之后依旧相切
P14248(树上边权修改求直径)
如何维护修改树上一条边的权值求直径?
首先随意选一个点为根计算所有点的深度\(dep_i\)
我们按照欧拉序计算,结果为
$ \max\limits_{i=1}^n \max\limits_{j=i}^n (dep_i+dep_j-2*\min\limits_{k=i}^jdep_k) $
我们考虑线段树进行维护对于每个区间\([l,r]\)维护5个值分别表示
$minn_x= \min\limits_{i=l}^rdep[i] $
$maxn_x= \max \limits_{i=l}^rdep[i] $
\(f_x=\max\limits_{i=l}^r(dep[i]-2*\min\limits_{k=i}^rdep[k])\)
\(g_x=\max\limits_{i=l}^r(dep[i]-2*\min\limits_{k=l}^idep[k])\)
\(h_x=\max\limits_{i=l}^r \max\limits_{j=i}^r (dep_i+dep_j-2*\min\limits_{k=i}^jdep_k)\)
pushup和修改都是好做的,直接转移即可
P3823(手写哈希表)
手写哈希表是比较好理解的,我的写法是线性探测,先随即赋值然后往后找到第一个空位统计,这里直接贴代码
struct Hash_Table{
int cnt[N*100],K=(1<<24),key[N*100];
bitset<N*100>fl;
ull s1,s2,s3;
void init()
{
s1=rnd();
s2=rnd();
s3=rnd();
}
ull getv(int x)
{
ull v=x+s1;
v=(v^(v>>33))*s2;
v=(v^(v>>30))*s3;
return v;
}
int gt(int x)
{
int i=getv(x)&(K-1);
while(fl[i]&&key[i]!=x)i=(i+1)&(K-1);
key[i]=x;fl[i]=1;
return i;
}
void insert(int x,int v)
{
cnt[gt(x)]+=v;
return ;
}
int query(int x)
{
return cnt[gt(x)];
}
}mp;
行列式应用
P7736
看似LGV引理,实则矩阵可做,太伟大了高等代数(
我们考率只有一个匹配时怎么做,不难发现要求的就是偶数减去奇数的数量,注意到这个东西和行列式本质上相同,直接用行列式即可。
那么有多层的时候怎么办呢。
比如设 $ f_i $ 表示偶数的数量,设 $ g_i $ 表示奇数的数量。
又注意到性质
$ (f_i-g_i)*(f_{i+1}-g_{i+1})=f_if_{i+1}+g_ig_{i+1}-f_ig_{i+1}-f_{i+1}g_i $
因为对于矩阵A、B来说
$ |A|\times|B|=|AB| $
也就是这两层合并起来的答案,于是我们可以选择用矩阵相乘解决这个问题。
最后计算最终的行列式即可
矩阵树定理
无向
对于无相图 $ G $ ,另 $ deg_i $ 表示 $ i $ 的度数,令 $ cnt_{i,j} $ 表示从 $ i $ 到 $ j $ 的边数。
构造矩阵 $ A $ 满足
\(A_{i,j}=\begin{cases}deg_i&i=j\\-cnt_{i,j}&i\neq j\end{cases}\)
令 $ A_i $ 表示 $ A $ 删掉第 $ i $ 行和第 $ i $ 列之后的矩阵
则该图的生成树为$ |A_i| $ 其中 $ i\in[1,n] $ (对于所有 \(i\) 结果相同)
有向
对于有向图 $ G $ ,$ cnt_{i,j} $ 与上面结果相同令 $ deg^{in}_i $ 表示 \(i\) 的入度, \(deg^{out}_i\) 表示 \(i\) 的出度。
则有
\(A^{in}_{i,j}=\begin{cases}deg^{in}_i&i=j\\-cnt_{i,j}&i\neq j\end{cases}\)
\(A^{out}_{i,j}=\begin{cases}deg^{out}_i&i=j\\-cnt_{i,j}&i\neq j\end{cases}\)
则对于一个点 \(k\) 来说,其叶向树为 \(|A^{in}_k|\) ,其根向树为 \(|A^{out}_k|\)。
BEST定理
如何计算一张图中的欧拉回路的数量(要求k开始k结束)?
首先入度都要等于初度。
然后其等于 \(|A_k^{in}|\times\prod\limits_{x\in V}(deg(x)-1)!\times deg(k)\)
LGV引理
链接
我看这篇文章是很好的,定义清楚,逻辑准确,只要作者变成我,就是一个很好的LGV引理博客了。
不过可以注意到,在大部分情况下边权都可以视为1,因此文中 $ e(i,j) $ 可以直接认为是从 $ i $ 到 $ j $ 的路径数
最小表示法
最小表示法核心在于其暴力的优化,我们注意到假如
$ s[i+k-1]>s[j+k-1] $
那么从 $ i $ 到 $ i+k $ 的所有点作为起点都不合法,直接移动到 $ i+k+1 $ 即可,最后复杂度为 $ O(n) $
虚树的一些应用
在有关树的题目中出现同一层或者与深度相关的贡献时,可以考虑建立虚树进行优化。
相关题目:0112模拟赛T2。
排列排序
关于排序的一个小性质:如果要在冒泡排序的方式下让交换次数达到理论最小值 $ \sum\limits_{i=1}^n |i-p_i| $ 。
那么原排列的最长下降此序列长度为2.
如何计数?
注意到对于数字 \(a_i\) 如果后面的数 \(a_{i+1}\) 比他小,那么 \(a_{i+1}\) 只能是在前 $ i $ 个数中没出现过的最小数。
以此为准开始计数,直接反射容斥即可。
线性基小技巧
如何保证线性基选出来偶数个?
直接加入 $ a_i \oplus a_1 $ 即可这样无论怎么选都是偶数个
关于概率期望问题中时停问题的相关思想
鞅与停时:CF1025G CF850F CF1349D CF1479E
思想:我们对于每种状态进行一次双射到一个集合 S 中,我们对于S设定一个函数 F(S) 使得对于每一步 状态A->状态B 都能满足 F(A)+1=F(B),那么我们的期望操作次数就是 $ F(S_{end})-F(S_{begin}) $
例题:CF1025G
我们将每种状态设置为每个可选节点孩子数的有序数列,那么我们令 $ F(S)=\sum\limits_i f(a_i) $ 其中 \(f(a_i)\) 表示一个有 $ a_i $ 个孩子的节点的权值。
由上面定义可得 $$ \sum\limits_i f(a_i)+1=\sum\limits_i \frac{1}{m(m-1)}((m-1)(m-2)f(a_i)+(m-1)f(a_i+1)+(m-1)(a_i-1)f(0))$$
整理可得\(1=\sum\limits_i \frac{1}{m}(f(a_i+1)-2f(a_i))\)
不妨钦定 $ f(a_i+1)-2f(a_i) = 1 $,递推即可
蚁群算法
这是一种基于贪心和历史最优解的随机化算法,由于过程有些复杂,直接放图了

关于容斥的一些理解
在容斥题目中,容斥系数都是逃不过的一环,那么我们应该如何计算这个系数呢?
我们不难发现,容斥实际上就是计算一个如下多项式
我们观察到,我们的容斥系数实际上就是后面哪一项的系数乘积,于是直接推就行了
与图论有关的小trick
一.竞赛图
竞赛图缩点后是一条链子,有一种图与其极其类似,及二分竞赛图,每对左部点和右部点之间都有一条有向边。
这种图缩点并按照环先后顺序排序后可以大致分为两类
1.大小>1,则只保留这种点可以视为链子
2.大小=1,若为同侧且在排序后相邻,则其连边终点完全相同。
二.二分图
如何在得到最大匹配后算出最小点覆盖的方案?
步骤:
在得到最大匹配的残余网络上,从起点延有流量的边做bfs,最终,左边所有没有访问过的点和右边所有访问过的点并起来就是最小点覆盖。
考虑原因:
1.所有点的两个端点,要么都被访问,有么都不被访问。
2.得出的点集一定是点覆盖。
3.得到的点数一定小于等于最大匹配。
因为一个匹配两端只有一个点会被选择。
所以这样就得到了他的最小点覆盖。
关于如何判断矩形
我们发现,对于所有2*2的方格,矩形的主要特点有如下几个
1.只有四个方格只包含1个点
2.不存在方格包含3个点
于是可以直接计算,这里提供一种很厉害的赋值方式:
1.每个点加入时权值+2
2.每个点加入时若与其相邻的点已经加入,则其相邻的点权值-2
3.若其对角的点已经加入,则对角的点权值+1
最后只需要计算后缀和最小是否为2即可判断是否构成矩阵
AT_abc305_h(WQS)
主要说一下WQS的部分,其中我们每次找到的是最大值,那么应该如何找最小值呢?
不难发现一段里面最小值wqs的权值一定和他相同,加入要求是 $ m $,最后答案是 $ f[n] $ 段数是 $ g[n] $ WQS二分结果为 $ v $ 则最小值就是 $ g[n]-(m-(f[n]-g[n]*v))/v $
莫队
集训特有的开了眼了环节
1.P6580
这道题不同的地方在于分块,他的核心想法是线段树合并,而线段树合并具有势能,于是对于势能进行分类,大于根号就重新开一段,以此为基础进行莫队
2.求 $ F(n,m)=\sum\limits_{i=0}^n \sum\limits_{j=0}^m C_i^j*[(i+j)=0(mod2)] $
这题看上去和莫队有锤子关系,但是注意到
$ C_n^0 + C_n^2 + …… + C_n^m $
= $ C_{n-1}^0 + C_{n-1}^1 + …… + C_{n-1}^m $
= $ \sum\limits_{i=0}^m C_{n-1}^i $
于是我们考虑行列的贡献,独立维护这两维,可以莫队。
3.实际上,由于莫队的时间复杂度分析和区间性质并没有直接关系,所以对于一个二元组(x,y)具有权值且它可以在O(T)的时间复杂度内进行一次由(x,y)向(x+1,y),(x-1,y),(x,y+1),(x,y-1)的转移,那么对于q个二元组,我们都可以在知晓第一个询问答案的情况下用 $ O(q\sqrt n T) $ 的时间复杂度内算出所有答案,高维同理
例题:arc228c
集合幂级数
感觉对哈基米级数的了解还停留在表面,目前来说主要是计算和含义
假如F(x)表示连通块权值,exp(F(x))就是不要求联通的权值。
计算主要是求逆,ln,exp
以下 $ f_i $ 表示集合大小为i所构成的多项式,这里挂下推导链接,直接看就行。
运算
平面图
定义:通过调整点使得任意两边不交的图为平面图
对偶图:将平面图的面视作点,再将原本相邻的面在新图上连边即可。
性质:
1.点数-边数+面数=2
2.平面图最小割=其对偶图最短路。
支配集
主要思想就是对于一线询问点对贡献的问题,可能存在部分点对是没有用处的,那么有用的点对就形成了支配集
例题:CF765F
计算 \(|a_i-a_j|\) 如果存在 \(i<j<k\) , \(a_i<a_k<a_j\) , $ a_j-a_i<(a_k-a_i)*2 $ 那么显而易见的 $ (i,k) $ 点对无用
因为如果你能选择 \((i,k)\) 那么你选择 \((j,k)\) 一定更优
点分治做法的时候不需要额外判断是否在一颗子树里面,因为这对答案不会产生影响。,
网络流
最大权闭合子图
什么是闭合子图呢,只需要保证当前点集内所有点的出边连向的点仍在这个点集内,那么这个点集就是一个闭合子图。
而对于一张点有点权,边无边权的图,应该如何计算他的最大权闭合子图呢?
考虑建立如下最小割模型(不妨认为i号点权值为v[i]):
- 对于源点,向每个正权点,连接一个流量为v[i]的边
- 对于每个负权点,向汇点连接一个流量为-v[i]的边
- 对于原图中条边,在模型中连接两个点,流量为inf
那么此时最小割表示的就是所有被删掉的正权与选择的负权的值。
用原本所有正权值减去最小割即可
类似于差分约束的建图
例题:P6054
如果题目中出现类似于"如果x选择i,那么y必须选择编号大于i+k的点",那么可以考虑这这种建图
将所有(i,j)->(i,j+1),边权为(i,j)的权值。
对于一个限制(x,y,k),将所有(x,i)连向(y,i+k)
但是此时依然存在一个问题,如何处理无解的情况,更具体的,如何强制让一个(i,j)-(i,j+1)的边上只选一个。
可以考虑链接(i,j+1)->(i,j)的流量为inf的边,此时一条边上选择两个部分割开就是毫无意义的了。
操作对区间贡献类问题(差分建图)
例题:P3980
这类题目中的一个操作会对应一个区间(也可以是类似区间的东西),同时对单个点的操作次数(或者类似的东西)进行约束。
这样来看一次操作的贡献会比较难以计算,考虑类似于差分的建图。
既然都差分了,那肯定是i->i+1,l->r+1连边
网络流一定要满足入度=出度,那么对于一个点i,只要他的出度为-a[i],就一定会在前面的点往后流至少a[i],否则不满足流的性质
基于这一点,我们可以按照如下方式建图:
- 链接i和i+1,边权为inf-a[i] (毕竟你不能真连一个-a[i]的全职吧)
- 对于每个操作(l,r),链接l-(r+1),流量为inf
这样最后的最大流就满足条件了。
上下界网络流
上下界网络流具体实现方法
笑了,第一个看到的上下界网络流是同学给我的/xk
例题:qoj17961
只要看出来他是一个线性规划问题还是比较容易想到建图的,需要注意的点只有删除操作可以直接视为向叶子连一条边,直接构造一个方案就行了
他还可以用来查询最少需要多少条可重复的路径可以覆盖图上所有边,只需要将所有必须经过的边的流量下界变成1就行
字典序最小最小割
例题
先跑网络流,然后保留残余网络之后缩点。这样所有的割边都有可能是最小割里面的。
假如现在确定了起点能到达的集合S,终点能到达的点T,假如有一个原图的边是从T连向S,那么一定不是最小割的一部分,直接舍弃,否则就可以构造最小割,然后更新S和T集合就行
浙公网安备 33010602011771号