OI题目类型总结整理
本蒟蒻的小整理qwq~~持续更新(咕咕咕)
数据结构
数据结构——线段树
推荐yyb dalao的总结——戳我
以后维护线段树还是把l,r写到struct里面吧,也别写len了,调试不好调qwq
初始化和叶节点初始化不太一样qwq,有的需要统一初始化的就一定注意不要写到if(l==r)里面qwq
- 求区间最大子段和 例题:codevs动态最大子段和
维护区间和,区间前缀最大子段和,区间后缀最大子段和,区间最大子段和。然后合并。(注意这种跨左右子树还有可能会有贡献的线段树写法上和普通的线段树不同!)、 - 求区间最大连续子段(比如说求一个区间内最长0子段的个数) 例题:SHOI脑洞治疗仪
维护区间前缀最大,后缀最大。然后合并即可。需要注意的一点是下面代码里面的取min(也就是带询问的区间更改一定要注意!前后缀长度是不能超过这个长度的):
if(rr<=mid) return query(ls(x),ll,rr);
else if(mid<ll) return query(rs(x),ll,rr);
else
{
int cur1=query(ls(x),ll,mid);
int cur2=query(rs(x),mid+1,rr);
int z1=min(t[ls(x)].maxr,mid-le[x]+1);
int z2=min(t[rs(x)].maxl,ri[x]-mid);
return max(max(cur1,cur2),z1+z2);
}
- 线段树模拟网络流 例题:codeforces280div.1D
这是个神仙啊!!!主要目的是为了优化时间复杂度,就是考虑最大费用流怎么跑的,我们用区间反转模拟退流过程即可。具体实现请看博文题解。时间复杂度\(O(klogn)\) - 一条链,两点之间有给出的距离,要求logn的时间复杂度内,求出一段区间中\(\sum\)任意两点之间的距离和。例题:HAOI高速公路
\(ans=\sum_{i=l}^r a[i]*(i-l+1)*(r-i+1)\)
\(ans=\sum_{i=l}^r a[i]*(-i^2+(r+l)i+(r-l+1-rl))\)
线段树维护即可 - 求历史最值(线段树模板3) 例题:CPU监控
将操作转换成(a,b),表示最终结果为min(x+a,b)。 - \(O(logn)\)时间复杂度求最长上升子序列的个数 例题:BZOJ楼房重建
- 在N个区间中选K个,使得它们的区间交至少为1,求最长区间长度-最短区间长度的最小值。 例题:NOI区间
先按长短排序,再按尺取法,不足K个的时候就加入到线段树中,如果满了就弹出前面的。 - 一棵树,每个节点都有颜色,有权值。支持对权值的更改,求树上某两个节点之间,拥有某一种颜色的节点的权值的最值或和。 例题:SDOI旅行
树链剖分,动态开点,给每一个颜色都建立一棵线段树。 - 将一个长度为n的序列分为k段,使得总价值最大。一段区间的价值表示为区间内不同数字的个数。\(n<=35000,k<=50\) 例题:CF833B
转移方程——\(f[i][j]=max(f[k][j-1]+Calc(k+1,i))\),然后线段树维护。 - 一张图分为两部分,左右都有n个节点,\(Ai->Ai+1\)连边,Bi->Bi+1连边,容量给出
有m对\(Ai->Bj\)有边,容量给出。两种操作
1.修改某条Ai->Ai+1的边的容量
2.询问从A1到Bn的最大流
\(n,m<=100000\),流量\(<=10^9\)。
线段树模拟网络流,转化成最小割——\(Ans=A_iA_{i+1}+B_j+B_{j+1}+A_xB_y(x<=i,y>j)\)。A如何更改不会影响到B一方的最小割选择,所以我们扫一遍A,在B中插入相应的值就行了。 - 两种操作,一种是令一个区间升序排列,一种是降序排列,求最后第K位上的数字。 例题:TJOI排序
二分这个值,然后比他大的置为1,其他的置为0,然后用线段树维护操作,看最后那个数是1还是0. - 两种操作,一种区间开方,一种区间加。(数值不超过1e5) 例题:UOJ基础数据结构练习题
区间开方转换成区间减维护。 - 区间开方
暴力即可 - 维护一个区间,两个操作
1.将区间\([l,r]\)所有数变为\(C^{ai}\)
2.求区间\([l,r]\)\(\mod p\)的和
例题:六省联考 相逢是问候
我们根据欧拉定理,知道反复进行若干遍操作之后,答案不会再变,所以提前预处理出所有的φ值。同时记录区间最少的操作次数,如果最小操作次数达到了上限,直接return。 - 给你一个数列,两个操作
1.给一段区间加上一个等差数列
2.将一段区间分解为最少个数的等差数列,输出等差数列的个数
例题:BZOJ1558等差数列
我们考虑对数列做差,这样如果是等差数列,那么值应该相等。我们设\(s[0],s[1],s[2],s[3]\)分别表示当前区间中,不考虑两端、不考虑左端点、不考虑右端点、两端都考虑,形成等差数列的个数。 - 扇形面积并,求被至少K个扇形覆盖的范围 例题:SHOI2013扇形面积并
转换成矩形,用线段树维护即可。
数据结构——线段树——线段树合并
一般线段树都是权值线段树,我们对权值线段树进行合并。
数据结构——线段树——李超线段树
放上自己的小整理
数据结构——主席树(可持久化线段树)
- 静态区间第K大 模板
- 带修区间第K大 例题:BZOJ1901
树状数组套主席树,主席树不需要继承历史版本,它的前缀和用树状数组维护了。 - 链上第K大 例题:BZOJ2588
平常的主席树是利用前缀和然后做差,现在放到树上就是树上差分。但是继承的时候注意要把继承上一个节点变成继承父亲的。然后用树上点差分即可。
数据结构——树链剖分
- 维护链上有向信息,如有向最大差 例题:TJOI2015旅游
就是维护前缀最大差,后缀最大差以满足有向的限制。最大差有两种选择方式。 - 如果有节点修改,修改过的节点随着操作次数增加依然增加,然后求两个点之间小于等于K的节点个数。 例题:SCOI情报传递
套主席树,但是操作过程中进行主席树上修改显然没有刚开始就离线处理得好。 - 每个节点都有一个颜色,求两点之间不同颜色段数(比如说11122113就是四段)
额外记录一个该区间最左端和最右端的颜色即可。
(如果不是节点有颜色,是边有颜色呢?)
数据结构——LCT
改变树的结构,记得要push_up。查询的时候一定要先push_down。
- 维护链信息(LCT上的平衡树操作)
- 动态维护连通性&双联通分量
- 如果是动态加边,用并查集维护会比findroot更快qwqwq
- 一定要注意有没有环出现!!!
- 维护边权(常用于维护生成树)
- 维护子树信息
- 维护树上染色联通块
数据结构——平衡树
- 为了让序列连续,我们可以将一般的splay插入的极小值(-2147483647)变成1,极大值(2147483647)变成n+2.
- 当一个数可能会对应很多意义(比如说人名?)就不要合并到一个节点里面了,分开建节点!
数据结构——左偏树
- 合并,求最值 例题:APIO2012派遣
- 维护子树信息(和其他树一样,维护add,mul标记,有push_down) 例题:JSOI城池攻占
数据结构——莫队
数据结构——莫队——普通莫队
一般都是对于计算出来区间[l,r]的值之后,能在O(1)或者差不多的时间中快速计算出\([l+1,r],[l-1,r],[l,r-1],[l,r+1]\)的问题。
- 给定一个序列,询问一个区间内不同数字的个数。
数据结构——莫队——带修莫队
先离线所有的操作,然后标记上修改的时间戳,还按照普通莫队做。如果当前处理的询问在上一个处理的时间之前,就还原之前的所有操作,如果在之后,就先进行之后的所有操作。
数学
数学——裴蜀定理
- \(\begin{cases}(n+m)a+(p+q)b=x\\(p-q)a+(n-m)b=y\end{cases}\)
n,m,p,q为未知解,求是否存在整数解?例题:HAOI向量
注意还需要进一步分类讨论n+m,n-m,p+q,p-q的奇偶性。
数学——欧拉定理(拓展欧拉定理)
- 给定n,每次使n等于φ(n),求最少几次操作后n=1。 例题:HAOI外星人
求出有多少个数作为因子即可。
数学——莫比乌斯反演
- 求\(gcd(i,j)=k,i\in[a,b],j\in[c,d]\)的个数 要求\(O(N)\)
- 求\(\sum_{i=1}^n\sum_{j=1}^md(ij)\) 要求\(O(N\sqrt N)\)
数学——莫比乌斯反演——公式与技巧
- \(i\in[1,n],j\in[1,m]\;then\;d(ij)=\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)=1]\)
- \(\sum_{i=1}^n\lfloor\frac{m}{k}\rfloor[x|gcd(i,j)]=\sum_{i=1}^{\lfloor\frac{n}{x}\rfloor}\lfloor\frac{m}{xk}\rfloor\)
- 求\(\sum_{i=1}^{n}\lfloor\frac{n}{i}\rfloor\)——整除分块
数学——BSGS
- 一般用来在\(\sqrt N\)的时间内,解决对于\(y^x\equiv z\pmod p\),给定\(y,z,p\)求x的问题。
数学——矩阵树定理
注意不合法的情况不需要给它赋id,直接跳过即可。
数学——容斥
ans=至多有n个-至多有n-1个+至多有n-2个......(奇加偶减)
- 求一个区间内(范围1e10)只包含数x,以及这些只包含数x的数的倍数的个数。 例题:SCOI2010幸运数字
先处理出来只包含数x的数都有哪些。lcm(i)表示是其中i个数的lcm。
ans=lcm(1)-lcm(2)+lcm(3)...... - 给定一个序列,每次只能删除一个数,删除到这个数列非降为止,问一共有多少种删法? 例题:BZOJ4361 isn
- 有障碍的网格图计数
对于一个确定的点(x,y),走到它的路径条数为\(C_{x+y}^x\)。
递推公式——\(dp[i]=C_{x[i]+y[i]}^{x[i]}-\sum_{j=1}^{i-1}dp[j]\times C_{x[i]-x[j]+y[i]-y[j]}^{x[i]-y[i]}\)
对于n个条件,一个都不满足的sum=sum(随便放/总数)-sum(至少满足其中1个条件)+sum(至少满足其中2个条件)-sum(至少满足其中3个条件)......
lucas定理
- 在\(O(n\sqrt n)\)的时间中快速计算\(f[n][k]=\sum_{i=0}^kC_n^i\pmod {2333}\)
\(=C_{n/p}^0\times \sum_{i=0}^{p-1}C_{n\%p}^i+C_{n/p}^1\times \sum_{i=0}^{p-1}C_{n\%p}^i+...+C_{n/p}^{k/p-1}\times \sum_{i=0}^{p-1}C_{n\%p}^i+C_{n/p}^{k/p}\times \sum_{i=0}^{k\%p}C_{n\%p}^i\)
\(=\sum_{i=0}^{p-1}C_{n\%p}^i\times(C_{n/p}^0+C_{n/p}^1+...+C_{n/p}^{k/p-1})+\sum_{i=0}^{k\%p}C_{n\%p}^i\)
\(=\sum_{i=0}^{p-1}C_{n\%p}^i\times \sum_{j=1}^{k/p-1}C_{n/p}^j+\sum_{i=0}^{k\%p}C_{n\%p}^i\)
\(=f[n\%p][p-1]\times f[n/p][k/p-1]+C_{n/p}^{k/p}\times f[n\%p][k\%p]\)
图论
图论——生成树
图论——生成树——kruskal生成树
例题:NOI2018归程\(\;\)peaks加强版
- 对于一个图,执行有关于从某个点出发的第几条小/大的边,或者从某个点出发小于/大于x的边不计算相关问题,强制在线。
图论——欧拉回路
- 给出一个有向图,问至少删掉多少条边使得这个图有欧拉回路。
设\(p_i=in[i]-out[i]\),如果\(p_i\),从S连向i,否则i连向T,容量为\(|p_i|\)。然后一条有向边\((u,v)\),网络刘忠
图论——基环树
对于一个n点n边的图,如果途中只存在一个环,则称之位基环树。细分则有基环树,基环内向树,基环外向树。
一般解决方法都是树形DP,然后对环部分进行环形DP。不然可以考虑断环法。
- 例题:NOIP2018旅游
- 例题:ZJOI2008骑士
- 例题:IOI2008island
图论——分层图
- 在一张图上移动,但是在相同的坐标位置因为其他一些条件的约束,有不同的状态。
图论——网络流
图论——网络流——最大流
- 常用建图模型1:对于一个点多种状态的(比如说在不同时刻状态意义不一样),可以把这个点拆成n个点,来分别表示不同时刻的状态。
- 询问最大流的几种方案中最长边的最小值 例题:SDOI费用流
二分+限流跑dinic - 在 \(n \times m\) 的矩阵中取出 n 个不同行且不同列的数,求取出的 n 个数中第 k 大的最小值。 例题:SCOI2015 小凸玩矩阵
转换求最大数的最小值,二分一个值,只要有n-k+1个数小于等于它即可。考虑网络流求最大匹配。S向行连边,列向T连边,如果某个数字小于等于二分的值,将它的行列连边。
图论——网络流——最小割
一般都是最优化问题的决策问题的解决利器。很多题目利用总点权(或者说所有正权点的和)-最小割来解决问题。qwqwq
- 最大权闭合子图模型
- 出现环怎么办。缩点,给每个强连通分量里面的点都连一条-inf的边到T。(NOI植物大战僵尸)
- 切糕模型 (给定一个立方体,它被分成pqr个格子,每个格子中都有一个数字,相邻地选择数字,每一行每一列都要选择一个数字。要求这些数字和最小。)
- 建r+1层,然后这些边的权值是对应位置的数字权值。从每一个点(第z层)向它旁边四个纵轴连一条指向第z-d层的有向边
- 带组合的决策问题 (给定n个点,每个点放进集合A有收获,放进B有对应收获,一些点组合起来一起放进A或B有额外收获,问最大收获?)
- 如果处理额外收获?最小割,割掉表示不选。每个组合建对应集合个的新点,新点连对应集合的点INF。如果是问最小收获?直接把取值反成n-ci按原来的求,之后答案再还原一下即可。
- 方格中有节点,每一个节点和周围的一些点不能共存,现在计算最多可以选出多少个节点。
权值为1的最大点权独立集——总权值-最小割。 - 平面图最小割=对偶图最短路(降低复杂度)
图论——网络流——费用流
- 一张图,起点是1,终点是n,问起点到终点再从终点到起点,每个点只能被访问至多一次,问一来一回最多能经过多少节点。 例题:航空路线问题
一来一回==从起点出发两次。最大费用流,拆点,中间流量为1,费用为0,强制u+n向v连边。但是要注意的是,有可能最佳方案是从1到n然后再到1,所以不能对于每条可行的线路的容量设置为1,因为这样的话就再也无法回来了qwq。 - 早上订货,可以定很多,每天早上的每单位的货有一个可能不同价格。每天必须保证至少x的供应量,货可以囤积到之后的天,但是量不能超过s,而且每单位需要支付一定的价钱p。
裂点,分成早晚两个。S向早上连容量INF的边,早上向T连容量为供应量,费用为0的边。早上向晚上连容量s的边,晚上向次日早上连容量s,费用为p的边。最小费用最大流。 - 如果是一条边只能取一次,就连一条容量为1,费用为收益的边,再连一条容量INF,费用为0的边。
- 如果是一条边的费用为诸如容量\(^2\times\)收益的这种不好计算的,考虑拆边,统一容量为1。
注意网络流一定不要因为数组开小而GG!!一定一定要注意边的数量,开够数组!!!
图论——其他
动态规划
动态规划——背包
动态规划——树形DP
- 每一个数都有一个父亲,必须自己的父亲先安装才能安装自己。每一个数安装都有安装所需空间和获得效益,现在给定最大可用空间,求最大效益。例题:HAOI2010 软件安装
可能成环,要么全装要么一个不装,所以先tarjan缩点,注意缩点之后把缩得的点连上这个环里面其他点连出去的边。然后就是一个树,做树形DP即可。
动态规划——树形DP——虚树优化
- 保留有效信息(如询问点和LCA),一般都出现在有询问点总和的条件约束的题目中。
动态规划——区间DP
- 给定一个序列,可以删除大于1长度的,连续的,形成等差数列的数,删完之后两边拼合,求最后最少能剩下多少个数?
无论怎么删,总是能拆成删若干次两个的+若干次三个的。所以区间DP+分类讨论即可。 - n个数,对于每一个数i,有ai个数比它大,有bi个数比它小,可能有相同数出现。问最小的不合法约束数量? 例题:HAOI problem a
做一个转化,每一个数的约束条件都是一个区间,这个区间内他们的数值都相同。每个区间都有一个权值,然后线性地DP即可。不过注意一个区间内最多有min(对应区间为此的数的数量,r-l+1)。
动态规划——区间DP——有决策点的DP
- 已知[1,x]区间里有东西,每次可以从[1,n]区间中以a[i]的代价询问该点是否有东西,求最坏情况下能确定x所需要的代价? 例题:挖油,要求\(O(N^2)\)
区间DP+优化。主要是用优先对列将其从\(O(n^3)\)优化到\(O(n^2)\),用n+1个优先队列维护该点状态主要从哪一种(作为最坏的)转移而来,1个维护固定左端点的,每次更换枚举的i时清空。n个维护固定右端点的,无需清空。
动态规划——DP套DP
某些DP问题的子问题不能简单地解决,而必须用另一个DP解决的问题。
即:外面的DP的状态是存的里面的DP各个状态的值,利用里层的状态来判断外层的DP是否合法,类似的问题有LCS为定值的序列的方案数等等。
-例题:hero and devil
动态规划——DP优化——单调队列
动态规划——DP优化——单调栈
动态规划——DP优化——矩阵加速
动态规划——DP优化——决策单调性
动态规划——AC自动机上DP
其实可以把AC自动机看作一个DAG,所以这个也就是DAG上的DP问题了。
- 给定一个数n,以及一些模式串比如说“123”(都没有前导零)。问从1到n的数中有多少个数的十进制表示中没有出现任何子串为给定模式串?\(n\le10^{10^{18}},m\le10\)
AC自动机上DP+矩阵快速幂优化递推 - 上一个问题,有前导零。\(n\le2e5,m\le 200\) 例题:SDOI数数
分成一类为没有长度限制的(即长度在n的长度以内的),一类为长度正好为n的,然后又分两种,一种是当前位已经达到限制,一种是还未达到限制。递推转移即可。
动态规划——其他
- 快速约瑟夫环
我们知道约瑟夫问题的通式一般都是这个样子的——\(dp[i]=(dp[i-1]+k)\mod i\),时间复杂度是\(O(n)\)的。但是如果我们想要\(O(logn)\)的做法呢?如果\(f[i-1]+k\)不超过i的时候,我们可以一次多加几个。 - 一个n*m的矩阵,可以选择其中一个数字进行修改(当然也可以不修改),求最大/最小矩阵和。
记录行/列最小值/最大值方便替换,记录一个不修改的最大/最小矩阵和和一个带修改的最大/最小矩阵和。 - 一个n*m的矩阵,可以选择其中一个数字进行修改(当然也可以不修改),使得矩阵的最大子矩阵尽可能小。
DP+分类讨论 - 最长公共子序列的长度和最长公共子序列的个数。 例题:HAOI2010最长公共子序列
长度很好做.\(len[i][j]=max(len[i-1][j],len[i][j-1])\),\(if(a[i]==b[j]) len[i][j]=len[i-1][j-1]+1\)
个数则\(sum[i][j]+=sum[i][j-1]+sum[i-1][j]\)
\(if(len[i-1][j-1])+1==len[i][j]\) \(then\;sum[i][j]+=sum[i-1][j-1]\)
\(if(len[i-1][j-1]==len[i][j]\) \(then\;sum[i][j]-=sum[i-1][j-1]\) - 坐座位,每个人都有一个编号,大家按照次序进入,从自己的编号开始做,如果位置被占了就顺次向后移动,直到找到一个空座位为止。事先有些人的为止已经预定过了不能更改。现在要给没有预定座位的人赋编号,问有多少种方案? 例题:HAOI problem c
显然编号确定了之后,坐座位的序列就是唯一的了,所以我们要给不同的人安排编号来使得方案不同。
设\(dp[i][j]\)表示第i个人之后,除去那预先预定过座位的人,我们给j个人制定了座位。\(dp[i][j]=dp[i+1][j-k]*C_j^k\),时间复杂度\(O(n^3)\)。 - 最短路上DAG计数(这里指经过边的计数) 例题:HAOI道路
- 先拓扑排序,然后按照次序正着DP一次,反着DP一次,乘起来即可。
字符串
字符串——哈希
字符串——KMP
字符串——manacher
字符串——AC自动机
一般AC自动机是解决字符串匹配一类的问题。
- 求一些模式串(不重复)有没有在文本串中出现过
- 求一些模式串(不重复)在文本串中出现多少次?最多的是哪个串?
- 求一些模式串(有重复)在文本串中出现多少次?例题:TJOI单词 \(n\le200\),模式串总长度\(\le1e6\)
暴力跳fail肯定会T,所以我们按dfs序从后往前遍历,往自己的fail边指向的节点累加答案。 - 求有没有可能存在一个无限长的串,使得其中不包含给定的一些文本串——也就是说不存在一个串,无法匹配给定的这些文本串。
尽可能让模式串匹配。有fail指针就要往上面跳。可以证明如果存在这样一个串,那么加上fail边,AC自动机上一定会出现一个环。
字符串——SA后缀数组
字符串——SAM后缀自动机
后缀自动机一般都用于解决什么样的问题呢?
- 求一个子串不同子串的数量。
也就是\(\sum longest-shortest+1=\sum longest-parent.longest\) - 求两个字符串的最长公共子串。
计算几何
计算几何——凸包
计算几何——动态凸包
- 例题:HAOI防线修建
计算几何——最小圆覆盖
其他技巧
- 曼哈顿距离小于等于d的菱形可以通过更改坐标系(旋转45度)使其变成矩形。例题:BZOJ极光
- 求满足\(l_i\le L\)或者\(R\le r_i\)的\(i\)的数量,可以转化为以\(L,R\)为原点,求坐标在第二象限的点的个数,可以用线段树扫描线来做。 例题:ARC exhausted?
- 异或——异或一个数两次,就相当于没有对这个数进行操作。对于一个区间[l,r],我们设a[i]为前i个数的异或和,显然对于区间[l,r],a[l-1]^a[r]就是这个区间里面所有数的异或和。
- 二分,一般都是用来转化成判定性问题来简化问题的,或者出现“最大值最小”,“最小值最大”之类的字眼。
- 对于一个数x,区间[A,B]内它的倍数是⌊Bx⌋+⌈Ax⌉+1
- 环上问题一般都是断环为链,复制两倍
- 链上一个接一个的转移显然可以用倍增优化
- 尺取法(维护两个指针,以\(O(n)\)时间复杂度解决一类单调性问题)
--
一些读题上的问题
- 注意一些“请问在字符串A中字符串B出现了多少次,这些出现的位置只要有任何一个不一样就行了,所以用.find的时候pos+1而不是pos+length(B)
- 问第K大,就真的是从大到小第K个数!!