讲课
1.分治
common分治
也就是对于每个子问题,在中间划一刀,然后分成两段,把区间中从mid开始维护一些奇奇怪怪的值,一般来说是最大前后缀、最小前后缀什么的。在中间的交集处理完毕后开始递归两边。总的来说就是乱搞
- 切mid
- 处理越过mid的答案,统计
- 递归解决
二分
分数规划
普通二分学的好好地,突然开始鬼畜。
分数规划问题,统计值形为分式的表达式最值,一通转换后获得一个便于维护的表达式。
- 维护 a [ i ] b [ i ] \frac{a[i]}{b[i]} b[i]a[i]最大
- a [ i ] b [ i ] > = m i d \frac{a[i]}{b[i]}>=mid b[i]a[i]>=mid
- a [ i ] > = m i d ∗ b [ i ] a[i]>=mid*b[i] a[i]>=mid∗b[i]
- a [ i ] − m i d ∗ b [ i ] > = 0 a[i]-mid*b[i]>=0 a[i]−mid∗b[i]>=0
对就是这玩意。
然后就能开始乱搞了
最小区间圆覆盖
挂、、、
整体二分
例题询问第k大
二分答案<=mid的数有没有k个。
但好像不止如此,同学博客目前没看到解释的很清楚的,挂了挂了
cdq分治
听说精髓就是考虑左边对右边的贡献,它可以处理各种缺1缺点缺边缺答案缺正解(???)问题。
太过玄妙没有听谢谢
点分治
点分治效率优秀,无怪乎它找了重心作为起点,不然铁定是要T飞的。
区间上的分治找到一个中心点,处理了跨区贡献后递归子问题,而点分治的精髓也在于分治,将数据规模减小,每次递归成为子树的问题,边界处理没有问题。
是的,每次以重心为界处理并递归下每颗子树,重新求解重心,重新计算,看起来与区间分治差别不大的样子呢。
关于它与树形dp之间有一些共性,因为都是在节点上处理与子树的关系。但一般来说,树形dp的题多是可以用点分治解决,而点分治得问题自是麻烦些,但好像也是可以由树形dp解决。
个人而言,点分治这个算法最近才接触,树形dp相对而言熟悉些,更加熟练,但是点分治熟练掌握是十分重要的。
时间分治
刚才dls讲了一下,时间分治中,因为添加、删除很麻烦,所以用另一种方法:按时间。时间轴中,某值在[l,r]区间内存在。 这做法真令人头秃,这tm也能分治?
2.图论
- 1.最短路变种:
也就是动态删边删点最短路
- 动态删边。如果该边不在最短路径上不用管,如果在的话寻找最小替代,从断点处x,y,用dis[1,x]+dis[x,y]+dis[y,n]更新替代??
看起来是这么一回事,老师讲的没怎么听懂,这是我自己的理解。话说这题貌似是用cdq分治搞啊(算了不管了)
- 动态删点。对于该点不在路径上的情况依然不用考虑。而不在则寻找最小替代。题目中多出一个无环的条件,这题要
- 2.例1。
题目:给定⼀张有向带正权拓扑图,求有⼏条 1 到 N 的路径的长度<= 1 到 N 的最短路+K
暴力&正解:
- 设 f [ x ] [ L ] 表 示 1 x 路 径 长 度 为 L 设f[x][L]表示1~x路径长度为L 设f[x][L]表示1 x路径长度为L
- f [ x ] [ L ] − > f [ f[x][L]->f[ f[x][L]−>f[
- 要 求 L + d i s ( x , n ) − d i s ( 1 , n ) < = k ; 要求L+dis(x,n)-dis(1,n)<=k; 要求L+dis(x,n)−dis(1,n)<=k;
- d i s ( 1 , n ) < = d i s ( x , n ) + d i s ( 1 , x ) dis(1,n)<=dis(x,n)+dis(1,x) dis(1,n)<=dis(x,n)+dis(1,x)
- L + d i s ( x , n ) − ( d i s ( 1 , x ) + d i s ( x , n ) ) < = k L+dis(x,n)-(dis(1,x)+dis(x,n))<=k L+dis(x,n)−(dis(1,x)+dis(x,n))<=k
- L − d i s ( 1 , x ) < = k L-dis(1,x)<=k L−dis(1,x)<=k
- d i s ( 1 , x ) < = L < = d i s ( 1 , x ) + k dis(1,x)<=L<=dis(1,x)+k dis(1,x)<=L<=dis(1,x)+k
- 对 于 第 二 维 L , 有 效 取 值 只 有 k + 1 种 对于第二维L,有效取值只有k+1种 对于第二维L,有效取值只有k+1种
- 所 以 f [ x ] [ L − d i s ( 1 , x ) ] 所以f[x][L-dis(1,x)] 所以f[x][L−dis(1,x)](0~k)
- 路 径 长 度 d i s ( 1 , x ) + v ; 路径长度dis(1,x)+v; 路径长度dis(1,x)+v;
- f ( x , v ) − > f ( y , d i s ( 1 , x ) + v + w ( x , y ) − d i s ( 1 , y ) ) f(x,v)->f(y,dis(1,x)+v+w(x,y)-dis(1,y)) f(x,v)−>f(y,dis(1,x)+v+w(x,y)−dis(1,y))
- 求 f [ N ] [ d i s ( 1 , n ) … … d i s ( 1 , n ) + k ] 求f[N][dis(1,n)……dis(1,n)+k] 求f[N][dis(1,n)……dis(1,n)+k]
- 3.最短路变种2(删点):
??:
- 1.对于所有边,求出长度L,[sl,sr]线段树维护最小值
- 2.L=dis(1,x)+dis(y,n)+w
- 4.三元环计数:
1。
-
1.大小点:???
-
2.设原图为G[x]:d[1…n]
-
排序,关键字(d[i],i),求每个点是第几小。
-
D[x]:(x,y)
-
如果rank[x]<rank[y]: x->y
-
else rank[x]>rank[y]: y->x
-
|D[x]|<=sqrt(m)
伪代码(核心部分):
for 1 to x do
if (y∈D[x])res[y]=1;
for y∈D[x] do
for z∈D[y] do
ans+=res[z];
- 5.四元环计数
for x=1 to n // n
for y∈G[x]
for z∈D[y]
if(rank[x]<rank[z]) ans+=res[z],res[z]+=1;
- 6.例子
题目:你现在很想知道⼀个数列 A[1…N] 是啥,但是需要花费代
价去获取情报,你可以花费 Cost[L][R] 的值去得到 A[L…R]
的和,给定 Cost,求最少花费多少代价才能确定 A[1…N]
• N<=1000,Cost[L][R]<=10^9
解:
- 知道A[l…r]也就是知道S[r]-S[l-1]的值,(S为前缀和数组)
- 每次将l-1与r连边,表示可以互相推得。
- 要知所有关系,则将所有边加入后做一遍最小生成树,(因为要与1号相连)
prufer序列
表示一棵无根树与序列一一对应的关系。
- 构造:每次找到一棵最小的叶子,删去后加入与其相连的点到prufer序列中,直到最后只有两点。
- 用prufer序还原树的步骤:对于prufer序从前往后,每次找一个之后的prufer序中没有出现过且之前没有标记过的最小的节点,标记这个点,和当前prufer序的这个点连边,最后找两个度数不够的点,把他们连起来(其实就是顺着做prufer序的过程连边)。
- 容易得知,序列中出现次数+1就是该点度数。
欧拉回路
二分图
判断奇环,判断偶环
Hall引理
7.边的染色
8.练习题
3.字符串
KMP字符匹配
寻找最小循环节,(n-fail[n]也是循环节,s[1]=s[n-fail[n]+1]),也就是最长相等的前后缀。
- 寻找最小的P,使得s[i]=s[i-p];
- 纯循环节:n是n-fail[n]的倍数
例题
-
1. 给定⼀个字符串 S,对于每个前缀S[1…i]求出:有⼏对前后缀相等且
不重叠. |S|<=1000000 -
2. 给定⼀个 m 位数字串 S,求有⼏个⻓度为 n 的字符串 T,满⾜ S 不
是他的⼦串. m<=20. n<=10^9 -
3. 有⼀个串 S,给定 S[1…i] 的最⼩循环节 d[i],构造⼀个字典序最⼩的
S. |S|<=10^6 -
4. 有⼀个串 S,定义⼀个优秀的拆分是将⼀个串表示成 AABB 的形式,
求 S 的所有连续⼦串的优秀的拆分的个数之和. |S|<=2000 -
5. AC自动机
后缀数组
挂掉……[哭卿卿]
n ∗ ( n + 1 ) 2 − ∑ i = 1 n − 1 h [ i ] \frac {n*(n+1)}{2}-\sum_{i=1}^{n-1} h[i] 2n∗(n+1)−∑i=1n−1h[i]