正睿19暑期B班DAY2 分治x图论x字符串

注 本文中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 条边的⽆向图,求三元环个数

1564400687456.png

把所有点按照度数从小到大排序

然后从小点向大点连边(终点集为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

1564402331429.png

还是排序连边 四元环只会有上图三种情况(假设从小到大为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个位置
于是这就变成了一道数学题

本题公式

[ans = binom{n - 2}{sum} frac {sum!} {prod limits_{i = 1}^{n} d[i] - 1} * (n - cnt)^{n - 2 - sum} ]

本题难点其实是高精度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)

原文地址:https://www.cnblogs.com/hjmmm/p/11266286.html