注 本文中max[l, r]表示区间[l, r]中最大值 min[l, r]同理
Part 1 分治
- 经典例题
• 求所有区间的最⼤值之和
一个最大值,对L在它左边R在它右边的所有区间都有贡献 O(n)
• 求所有区间的最⼤值*最⼩值之和
对于一个区间|L --- mid --- R|
处理出[mid, R]中(min,max,min*max)的前缀和
然后对于(L leq i leq mid) 处理(Ma[i])表示对于(mid leq j leq Ma[i]) 有[i, j]中最大值为[i, mid]的最大值
由于Ma[i]单调减 这个东西可以线性处理 (Mi[i])同理
于是对于以下情况:|L-----i------mid---Mi[i]-----Ma[i]---R|(Ma[i]小的话也同理)
对于区间[l, r]如果(L leq l leq mid, mid + 1 leq r leq Mi[i]) 每个贡献为min[i, mid] * max[i, mid]
对于区间[l, r]如果(L leq l leq mid, Mi[i] + 1 leq r leq Ma[i]) 贡献用min前缀和计算
对于区间[l, r]如果(L leq l leq mid, Ma[i] + 1 leq r leq R) 贡献用min*max前缀和计算
(O(n log n))
• 求所有区间的 gcd 之和
因为一个玄学结论一个区间gcd不同的分段个数期望为(log(len))
所以就暴力分治就好啦(惊辽)(O(n log^3 n))
• 求⼆维平⾯上最近点对
先按照x坐标排序 中间切(假设是竖着切)
若递归得到的答案为ret
那么只需计算可能更新答案的点
在中间的切线两侧取水平宽ret 竖直高2*ret的矩形
计算该矩形中跨线点对就好啦
又有一个玄学结论说这个矩形中 中线的一侧期望有6个点
。。。
好吧
常数估计巨大?(O(n log n))
• 分治多项式乘法
就是拆成两份分开乘啦
- 旅⾏者
• 给定⼀张 n*m 的带正权⽹格图,有 Q 组询问,每次询问两对点之间的最短路
• 1<=n*m,Q<=50000
把询问离线 如果竖着长就横着切 反之亦然
然后对于中间线上每个点做一次单点最短路
然后更新询问 注意递归进来的所有询问都要处理 不只是跨线的
(O(S sqrt{S} log sqrt{S}))
- 连续区间
• 给定⼀个排列 p[1…n],求有⼏个区间 [L,R] 满⾜ p[L…R] 排序后是连续的
• n<=500000
如果要区间[l, r]连续 那么等同于(max[l, r] - min[l, r] = r - l)
类似于经典问题2
对于一个区间|L --- mid --- R|
然后对于(L leq i leq mid) 处理(Ma[i])表示对于(mid leq j leq Ma[i]) 有[i, j]中最大值为[i, mid]的最大值
对于区间[l, r]如果(L leq l leq mid, mid + 1 leq r leq Mi[i]) 合法右端点要求(r = l + max[l, mid] - min[l, mid])
对于区间[l, r]如果(L leq l leq mid, Mi[i] + 1leq r leq Ma[i]) 合法右端点要求(r - max[l, mid] = l + min[mid + 1, r])
对于区间[l, r]如果(L leq l leq mid, Ma[i] + 1 leq r leq R) 合法右端点要求(r - max[mid + 1, r] + min[mid + 1, r] = l)
等式左边的东西处理一下就OK啦 (O(n log^2 n ))
- XOR最⼩⽣成树
• 给定 n 个点,第 i 个点的点权是 a[1…n],现在定义边 (i,j) 的权值是 a[i] xor a[j],求最⼩⽣成树
relaxing啊,按照最高位向下划分就好啦
- 区间统计
• 给定 a[1…n],求有⼏个区间 [L,R] 满⾜ a[L] or a[L+1]…or a[R]>max(a[L…R])
• N<=3*10^5
• a[i]<2^30
预处理一个数a[i]左边第一个a[j]满足a[j] | a[i] != a[i]显然这个东西有单调性
然后如经典例题1来操作就好啦 (O(n) + O(n log n) = O(n log n))
Part 2 ⼆分与分治
- 经典例题
• 分数规划问题
• 给定 n 个点 x[1…n],要求将它划分成尽量少的连续区间, 使得每个区间的最⼩圆覆盖的半径<=S
众所周知,最小圆覆盖是一个(O(n))算法【雾】
然而直接二分是会被卡的 所以采用一种神奇的方式
先(check[l, l + 2^1]),然后是(check[l, l + 2^2])一直找到(check[l, l + 2^i])不能被合法圆覆盖了
有了范围再二分 (O(n log n))
• 给⼀个序列 a[1…n],要求选出恰好 K 个互不相交的区间, 使得权值之和最⼤
(被咕掉了。。)安利bzoj TREE
- 整体⼆分
• 有 N 个位置,M 个操作,每次操作是 1 a b c,或者 2 a b k
• 1 a b c 表示在第 a 个位置到第 b 个位置每个位置都加⼊⼀ 个数 c
• 2 a b k 表示询问第 a 个位置到第 b 个位置的第 k ⼤的值
• N,M,c<=50000
如题,整体二分。。
右转[CTSC2008]网络管理
- CDQ分治
• 三维偏序
• 矩阵加,矩阵求和
• 缺 1 背包问题:给定 n 个物品的重量 W[i] 和价值 V[i],Q次询问,每次询问对除了第 i 个物品以外的物01 背包后重量不超过 S 的最⼤价值 n,W,V<=2000. Q<=1000000
分治(solve(l, r, f_{l, r}))
(f_{l, r})表示除去[l, r]的背包结果
• 缺点最短路问题:给定 n 个点的带权⽆向图,Q 次询问,每次询问 X 到 Y 的不经过 Z 的最短路⻓度,N<=200,Q<=1000000
floyd第一维分治,与上一题的状态类似,(solve(l, r, f_{l, r}))
• 解递推式 f[n]=sum( f[i]*g[n-i] )(雾)
- 点分治
• 求所有边数<=L 的链的权值之和
• 给定⼀棵树,有 Q 次询问,每次询问离 x 距离 <=L 的点数
• 给定⼀棵树,每个点有物品重量 W[i] 和价值 V[i],求价值最⼤的重量不超过 S 的连通块,n,S<=2000
- 时间分治 (被咕掉了)
• 加边删边询问两个点是否连通
Part 3 图论
- dijkstra当 dis[x] 的⼤⼩在 10^7 内时怎么做?
把优先队列换成链表 把log强行去掉
- 如何卡SPFA算法
• 搞个⾏很少的⽹格图,竖着的边权很⼩,横着的边权很⼤
- [noip2016]逛公园
• 给定⼀张有向带非负权有环图,求有⼏条 1 到 N 的路径的⻓ 度<= 1 到 N 的最短路+K
• (N,M<=10^5,K<=100,边权<=10^9)
- 最短路变种
• 给定⼀个带权有向图,Q 次询问,每次询问删掉某条边后 1 到 n 的最短路
• 给定⼀个带权有向⽆环图,Q 次询问,每次询问删掉某个点后 1 到 n 的最短路
- 数环
• 给定⼀张 n 个点 m 条边的⽆向图,求三元环个数
把所有点按照度数从小到大排序
然后从小点向大点连边(终点集为D[i], 原图中终点集为G[i])
如果有三元环的话状态如图所示(假装从小到大是x, y, z)
所以就
$for i = 1 to n (维护)res[x][i]$ ((res[x][i])表示有边(x -> i))
(for x = 1 to n) for(int y : D[x]) for(int z : D[y]) ans += $res[x][z] $
(O(m sqrt{m}))
据说bzoj3498是板子
• 给定⼀张 n 个点 m 条边的⽆向图,求四元环个数
• n,m<=50000
还是排序连边 四元环只会有上图三种情况(假设从小到大为a, b, c, d)
发现这两种情况 都是从a先走一条有向边 再走一条无向边
(for x = 1 to n) for(int y : D[x]) for(int z : G[y]) (ans += res[x][z], ++res[x][z];)
(O(m sqrt{m}))
- 圈套圈算法
• 任选⼀个起点,从起点开始 dfs,每条边只能被⾛⼀遍,当没有边可以⾛的时候把 x 压⼊答案的队列中
• 最后的答案是反着的欧拉回路
- 树
• 树:N 个点 N-1 条边的连通⽆向图,分为有根树和⽆根树
• 树的叶⼦:度数为 1 的点
- 最⼩⽣成树
• 给定⼀张 n 个点的带权⽆向图,求权值和最⼩的⽣成树
• Kruskal 算法:将边按照权值⼤⼩从⼩到⼤排序,之后能加就加,⽤并查集维护
• 证明:证明权值最⼩的边⼀定在最⼩⽣成树中,然后归纳法
例题: 你现在很想知道⼀个数列 A[1…N] 是啥,但是需要花费代价去获取情报,你可以花费 Cost[L][R] 的值去得到 A[L…R] 的和,给定 Cost,求最少花费多少代价才能确定 A[1…N]
• N<=1000,Cost[L][R]<=10^9
每个区间[l, r]看作(edge(l - 1, r, cost[l][r]))
然后(装作以0为根)最小生成树就好了
- Prufer序列
• 将⼀棵树变成⼀个序列:
• 每次选择树上标号最⼩的叶⼦,删掉它,将与它相连的那
个点的标号加到序列⾥,直到只剩下 2 个点
• 可以证明:任意⼀个⻓度为 n-2 的 1…n 的序列都是某棵树
的 Prufer 序列
• 所以可以推出:n 个点的⽆根树个数为 n^(n-2)
例题:给定每个点的度数 d[i],求有⼏棵这样的⽆根树。
(frac{(n - 2)!}{prod_{i = 1}^{n} (d[i] - 1)!})
扩展安利:
明明的烦恼
本题相当于问根据给出的度数 有多少种prufer序列可以被生成
对于一个度数为x (x >= 2) 的点 显然它要在prufer序列里占x - 1个位置
于是这就变成了一道数学题
本题公式
本题难点其实是高精度qvq
- ⼆分图
• 可以分成两部分,使得这两部分内部没有边的图
• ⼀个图是⼆分图等价于该图没有奇环
• prob1. 判断⼀张图是否有奇环
• prob2. 判断⼀张图是否有偶环
- ⼆分图
• 最⼩顶点覆盖:选最少的点覆盖所有边
• |⼆分图最⼩顶点覆盖|=|⼆分图最⼤匹配|
• 最⼤独⽴集:选最多的点使得它们两两没边相连
• |⼆分图最⼤独⽴集|=总点数-|⼆分图最⼩顶点覆盖|
- Hall 引理
• 设 S 是左边点的⼀个⼦集,设 N(S) 为 S 所有点邻居的并
集,则⼀个⼆分图存在完美匹配的充要条件是:
• 对于所有 S,|S|<=|N(S)|
- Hall 定理的应⽤
• 给定⼀个 [n,n] 个点的⼆分图,每条边有边权,要求删去边
权和最⼩的边集,使得这张图没有完美匹配
• n<=18
这道题没有多项式算法 只能枚举左边的子集 暴力Hall
- 选择
• 给定 n 个数对 (x[i],y[i]),你需要构造⼀个数组 s[i],满⾜ s[i] 是 x[i] 和 y[i] 中的其中⼀个,且 s ⾥没有重元素,顺便数个⽅案数
• 1<=n<=10^6
可以看作一些树和一些环套在一起
【坑】
- 边的染⾊
• 给定⼀张⽆向图,边有边权且为0或1,有些边的边权还没
有确定,现在需要你确定这些边的边权,使得满⾜所有环
的边权的异或值都为0,求⽅案数
• 1<=n,m<=10^5
设一个边的边权为两端点权异或和
然后环上的异或和必然为零啦
因为每个点权被计算了两次
- 练习题
• 有⼀个 (N*M) 的矩形,其中有 K 个格⼦中有病毒,现在你可以进⾏若⼲次消毒,每次你可以选择⼀个任意⼤⼩的⼦矩形进⾏消毒,假设是 (A*B) 的矩形,则代价是 min(A,B),要求你⽤最少的代价进⾏消毒
• N,M,K<=5000
行列建点 最小点覆盖等于最大匹配
Part 4 字符串
- 例题
• 给定⼀个字符串 S,对于每个前缀S[1…i]求出:有⼏对前后缀相等且不重叠. |S|<=1000000
右转NOI动物园
• 给定⼀个 m 位数字串 S,求有⼏个⻓度为 n 的字符串 T,满⾜ S 不是他的⼦串. m<=20. n<=10^9
模拟fail,矩阵乘法加速
• 有⼀个串 S,给定 S[1…i] 的最⼩循环节 d[i],构造⼀个字典序最⼩的S. |S|<=10^6
对于第i位,若S[i]使得fail[i] > d[i]那么S[i]就不能用 要大一点
• 有⼀个串 S,定义⼀个优秀的拆分是将⼀个串表示成 AABB 的形式,求 S 的所有连续⼦串的优秀的拆分的个数之和. |S|<=2000
骗分般优秀的拆分 从中间分开统计pre[i] (AA个数)+ suf[i + 1](BB个数)
至于pre的预处理 hash暴力就好啦
• Trie上的KMP:AC⾃动机
- 后缀数组常规操作
• LCP(X,Y)=Min(H[rk[x]]…H[rk[y]-1])
• 最⻓重复⼦串
(height[ ]_{max})
• 不可重叠最⻓重复⼦串
二分一个长度 用height check一下
• 本质不同的⼦串个数
(n(n + 1) / 2 - sum_{i = 1}^{n} height[i])
• 求 S[l…r] 的出现次数
从l向下找有多少个(height[i] >= r - l + 1)