2020多校补题

牛客1

A

1.性质
求出每个后缀对应的b数组,会发现:后缀的b数组,就是在原字符串的b数组的基础上,把一些值改为0。

2.分类讨论
进一步分析发现b数组中,最多存在两个0,所以只要根据0的位置,来判断两个b数组的大小,最后通过改写比较级进行排序就可以了。

3.后缀数组
分类讨论时发现要比较两个后缀的大小,这时就可以套用后缀数组的模板,得到排名,来比较大小。

H

1.判断是否合法
先计算容量为1时的最大流m,当容量变为 u / v u/v u/v时,最大流变成 m ∗ u / v m*u/v mu/v(容量和最大流成比例)。接着判断 m ∗ u / v m*u/v mu/v是否大于等于1。

2.按比例计算费用流
跑一次增广路时,增加1个单位(以边容量为1个单位)的费用,所以把:跑每一次增广路时的费用记录下来。接着把流量1按照边容量 u / v u/v u/v为基本单位,分配费用。为了方便计算,就变成了:把流量v按照边容量u为基本单位,分配费用,结果再除以v。

I

1.转化为匹配问题。
用“度拆点”,“边拆点”的技巧建图,转化为匹配问题。

2.建图
“度拆点”:把同一个点的多个度数拆成多个点
“边拆点”:把边的两个端点拆成两个点
“连线”:度数的点连接对应的边的端点,两个边的端点互相连接。

3.跑一般图匹配
建好图后,用带花树算法得到匹配。如果是完美匹配(所有点都被匹配到),就说明存在,否则不存在。

4.匹配边的意义
如果一条匹配边,一个端点是度数的点,另一个端点是边的端点,代表着边对应的点被选上了。如果一条匹配边,两边都是边的端点,代表着边对应的点没被选上,删去这些没被选上的边,就可以得到答案了。

牛客2

A

1.枚举+桶
考虑枚举所有字符串的前缀,然后找有多少个字符串的后缀与这个前缀相同。解决方法:计算出每个字符串的后缀hash值,然后存到桶里面。

2.去重
上述方法会重复计算一些情况。原因是:在枚举一个字符串的前缀时,可能会有不同前后缀,但是匹配到同一个字符串的问题。例如当前字符串为:aba???,因为a既是aba的前缀,也是aba的后缀,所以在枚举前缀时会算重复。解决方法:用kmp的next数组去重。

B

1.性质
找任意两点的中垂线的交点,相同交点数最多的就是答案

2.优化
因为用的是map,所以map不能装太多点(小于1e6),否则容易超时。所以,在枚举一个点,先记录下与其它的点的中垂线交点,放到map里面,然后算出答案,清空map后,再枚举下一个点。

H

1.分类讨论
可以把 M S MS MS看成是一个排好序的序列,首先知道:三角形判断的充要条件是:最小两边和大于第三边,然后对 a , b , x a,b,x a,b,x的大小进行分类讨论(假设 a ≥ b a \ge b ab):

(1) b ≤ a ≤ x b \le a \le x bax:这时直接找离 x x x最近的两个数,即 x x x的两个前驱,这两个前驱就是 a , b a,b a,b,然后判断 a + b a+b a+b是否大于 x x x即可。

(2) b ≤ x < a b \le x < a bx<a:根据大小关系,我们要找的 a , b a,b a,b应该满足: b + x > a b+x>a b+x>a,即: x > a − b x>a-b x>ab,意思就是要使 a − b a-b ab尽量小。又因为 a , b a,b a,b x x x的两边( b ≤ x b \le x bx x ≤ a x \le a xa),所以选 x x x的前驱作为 b b b x x x的后驱作为 a a a是最优的。接着判断是否符合三角形的要求就可以了。

(3) x < b ≤ a x < b \le a x<ba:同(2),要找满足: x > a − b x>a-b x>ab a , b a,b a,b。即查找 M S MS MS中,大于 x x x的数的部分的最小差。

2.求 1(3) 中的最小差
用数据结构优化的思路是:把要维护的东西看成是有序的序列,然后才用数据结构,去维护这个有序的序列。
(1)平衡树(题解做法)
平衡树的性质:左子树所有的节点小于当前节点,右子树所有的节点大于当前节点。
平衡树每个节点维护的内容:当前节点与前驱的最小差 d t dt dt,子树中所有节点 d t dt dt的最小值。

插入和删除的时候并不难,在回溯时就可以更新维护的内容。查询的时候,首先找到 x x x的后驱在平衡树的位置,叫节点 p p p。因为要找的是:大于 x x x的部分的最小差,所以,我们可以从 p p p开始,找 p p p的右子树(平衡树性质)的最小 d t dt dt值。因为大于 x x x的数不单只有 p p p的右子树部分,所以 p p p还要往根节点的方向走,统计合法的 d t dt dt值,具体自行画一下图(牢记平衡树性质)。

(2)权值线段树(自己的做法)
权值线段树维护的内容:当前区间(数值范围)数的数量,最大值,最小值,最小差(类似查询全局最小差,我是参考这里的)。问题由全局最小差,变成了区间最小差。

区间最小差要注意的地方:因为询问一个区间时,会被线段树拆成很多个区间,但是线段树并没有记录这些拆的区间,之间的最小差,所以要手动解决。我的方法:把线段树拆成的区间中的最大值和最小值加入到一个 n u m num num数组,排序去重后直接 O ( s i z e ( n u m ) ) O(size(num)) O(size(num))算最小差。因为线段树拆出来的区间不多,所以这样的做法还是挺快的。注意:不要把不存在的最大值和最小值加入到 n u m num num

牛客3

D

1.性质
对于每行(每列)来说,从左到右,一定是:一堆白点->一堆黑点->一堆白点相间,而且起始和末尾都是白点,所以对数一定是偶数(一堆黑点和左边白点会产生一对,一堆黑点和右边白点又会产生一对)。

2.判断是否合法
由1的性质可知m必须是偶数,否则不合法。
m的最大值 m m a x mmax mmax 4 ∗ n 4*n 4n,因为一个黑点最多和上下左右四个白点组成一对。
m的最小值 m m i n mmin mmin:因为需要匹配的对数少,所以考虑把黑点放在一起,所有黑点都在a行b列内,且按顺序(从左到右,从下到上)摆放。a和b需要满足的条件: a ∗ b ≥ n a*b \ge n abn 2 ( a + b ) = m m i n 2(a+b)=mmin 2(a+b)=mmin。通过这个条件,我们使 2 ( a + b ) 2(a+b) 2(a+b)尽量小,就可以求出m的最小值了。

3.构造合法的解
在算m的最小值时,就已经构造出了解的一部分。如果现在的m是最小的,那么就已经得到了答案。如果现在的m不是最小的,就从最后一个黑点开始,把这个点扔到很远的地方。如果这个点是一行(列)中最后一个点,那么可以增加: 4 − 2 = 2 4-2=2 42=2个对(由1的性质可知),否则增加 4 4 4个对。重复这个操作,直到对数大于等于m。如果对数大于m,这时对数肯定只比m大 2 2 2,则把刚刚扔出去的其中一个黑点,与其他任意一个黑点相邻,使对数减 2 2 2,就得到答案了。

E

1.题目本质
由于题目说 p p i = i p_{p_i}=i ppi=i,所以有: a p i − a p p i = a p i − a i a_{p_i}-a_{p_{p_i}}=a_{p_i}-a_i apiappi=apiai。所以就是找数组a的两个数相匹配,所以题目变为:给出一个a数组,找到两种不同的匹配方法,使这两种匹配方法得到的和最小。

2.性质
匹配时,会发现连续4个,或者连续6个为一组进行匹配,情况是最优的。

3.dp
对于当前位置,是选择连续4个,还是连续6个,可以用dp解决。

F

1. g c d ( a , b ) > 1 gcd(a,b)>1 gcd(a,b)>1
随便选一个大于1的公因子 g g g,则:
a / b = ( x g ) / ( y g ) = ( x + 1 ) g / y g − g / y g = ( x + 1 ) / y − 1 / y a/b=(xg)/(yg)=(x+1)g/yg-g/yg=(x+1)/y-1/y a/b=(xg)/(yg)=(x+1)g/ygg/yg=(x+1)/y1/y接着对应套上去就可以了。

2. g c d ( a , b ) = 1 gcd(a,b)=1 gcd(a,b)=1 b b b的质因子个数大于1
通分一下题目的公式,得:
( c f − e d ) / ( d f ) = a / b (cf-ed)/(df)=a/b (cfed)/(df)=a/b令: d f = b df=b df=b,然后求出符合条件的 d , f d, f d,f g c d ( d , f ) = 1 gcd(d,f)=1 gcd(d,f)=1
接着,令: c f − e d = a cf-ed=a cfed=a,因为 g c d ( d , f ) = 1 gcd(d,f)=1 gcd(d,f)=1,所以此方程必定有解。接着就用扩展欧几里得求出 c , e c, e c,e就可以了。要注意的是:扩欧求出来的 c , e c, e c,e不一定大于0,所以要记得转化一下。

3. g c d ( a , b ) = 1 gcd(a,b)=1 gcd(a,b)=1 b b b的质因子个数为1
无解。证明:设 b = p k b=p^k b=pk p p p为质数,则: d = x p k 1 d=xp^{k_1} d=xpk1 f = y p k 2 f=yp^{k_2} f=ypk2,所以:
c d − e f = c x p k 1 − e y p k 2 = c p k − k 1 − e p k − k 2 x y p k \frac{c}{d}-\frac{e}{f}=\frac{c}{xp^{k_1}}-\frac{e}{yp^{k_2}}=\frac{cp^{k-k_1}-ep^{k-k_2}}{xyp^k} dcfe=xpk1cypk2e=xypkcpkk1epkk2因为: k 1 , k 2 < k k1,k2<k k1,k2<k,所以: k − k 1 > 0 k-k_1>0 kk1>0 k − k 2 > 0 k-k_2>0 kk2>0
即:下面的 p k p^k pk还可以被约,但是因为 g c d ( a , b ) = 1 gcd(a,b)=1 gcd(a,b)=1,所以分母必须保留 p k p^k pk这个因子,这与 p k p^k pk被约矛盾,所以无解。

牛客6

H

1.数位dp
记忆化搜索中,数位dp的必备状态:搜索的数位位置 p o s pos pos,搜索位的限制 l i m i t limit limit。这道题的数位dp的状态:搜索的数位位置 p o s pos pos,搜索到当前位的 A A A B B B的数位和的差 d e l t a delta delta。又因为 A ≤ B A \le B AB,所以还要有两个 l i m i t limit limit变量: l i m i t A limitA limitA l i m i t B limitB limitB。接下来,只需要在当前位 p o s pos pos,根据 l i m i t A limitA limitA l i m i t B limitB limitB,枚举 A A A B B B的数位,剩下的套数位dp模板就可以了。转移方程(建议先自行思考):

p o s > 0 : pos > 0: pos>0
d f s ( p o s , d e l t a , l i m i t B , l i m i t A ) dfs(pos, delta, limitB,limitA) dfs(pos,delta,limitB,limitA) = ∑ 0 ≤ i ≤ u p B ∑ 0 ≤ j ≤ u p A d f s ( p o s − 1 , d e l t a + j − i , l i m B , l i m A ) , =\sum\limits_{0 \le i \le upB}\sum\limits_{0 \le j \le upA} dfs(pos-1,delta+j-i,limB,limA), =0iupB0jupAdfs(pos1,delta+ji,limB,limA), u p B = { n u m [ p o s ] limitB = 1 9 limitB = 0 , upB= \begin{cases} num[pos]& \text{limitB = 1}\\ 9& \text{limitB = 0} \end{cases}, upB={num[pos]9limitB = 1limitB = 0, u p A = { i limitA = 1 9 limitA = 0 , upA= \begin{cases} i& \text{limitA = 1}\\ 9& \text{limitA = 0} \end{cases}, upA={i9limitA = 1limitA = 0, l i m B = { 1 i = upB and limitB = 1 0 other , limB= \begin{cases} 1& \text{i = upB and limitB = 1}\\ 0& \text{other} \end{cases}, limB={10i = upB and limitB = 1other, l i m A = { 1 j = upA and limitA = 1 0 other limA= \begin{cases} 1& \text{j = upA and limitA = 1}\\ 0& \text{other} \end{cases} limA={10j = upA and limitA = 1other p o s = 0 : pos = 0: pos=0 d f s ( p o s , d e l t a , l i m i t B , l i m i t A ) = { 1 delta > 0 0 other dfs(pos, delta, limitB,limitA)= \begin{cases} 1& \text{delta > 0}\\ 0& \text{other} \end{cases} dfs(pos,delta,limitB,limitA)={10delta > 0other

2.细节
(1)存数位和的差时,小于0的差一定也要记录,这样才能覆盖整个解空间
(2)有些数位dp模板可能没有记忆化 l i m i t limit limit变量。在这道题中, l i m i t A limitA limitA l i m i t B limitB limitB也要记忆化,不然会超时
(3)dp数组一定要初始化为-1

牛客9

J

1.查询矩阵和
考虑用二维前缀和, s u m [ n ] [ m ] sum[n][m] sum[n][m]代表 ∑ 1 ≤ i ≤ n , 1 ≤ j ≤ m a i , j \sum\limits_{1\le i \le n, 1 \le j \le m} {a_{i,j}} 1in,1jmai,j,预处理后就可以通过 s u m sum sum得到任意一个子矩阵的和。在这之前,先要把矩阵 a a a中的 0 0 0,修改成 − 1 -1 1。目的是:能让后面用“桶”统计答案。

2.枚举矩阵
普通枚举矩阵的方法:枚举矩阵的上下行,左右列。在这里因为要更快统计答案,只枚举了矩阵的上下行,右列

3.统计答案
假设已经枚举了矩阵的上行 U U U,下行 D D D。接着考虑前缀和维护: s u m 2 [ R ] sum2[R] sum2[R]代表 ∑ U + 1 ≤ i ≤ D − 1 , 1 ≤ j ≤ R a i , j \sum\limits_{U+1\le i \le D-1, 1 \le j \le R} {a_{i,j}} U+1iD1,1jRai,j,这样就可以通过 s u m 2 sum2 sum2的前缀和相减,得到子矩阵和。因为题目要求子矩阵内 0 0 0 1 1 1的数量差值不超过 1 1 1,所以子矩阵内的和在 [ − 1 , 1 ] [-1,1] [1,1]内。即可以转化为:如果 s u m 2 sum2 sum2中存在两个值的差值不超过 1 1 1,那么这两个值可以贡献一个答案。
要统计有多少对值的差值不超过 1 1 1,可以考虑在连续为 1 1 1的上下行中,枚举 s u m 2 sum2 sum2中的值(右列),把满足列全为1 s u m 2 sum2 sum2值(左列)放进 c n t cnt cnt里面,询问 s u m 2 sum2 sum2的值加 1 1 1、加 0 0 0、减 1 1 1的值的数量。

4.桶的处理
如果用map/unordered_map,很可能会超时。因为考虑到前缀和的范围: [ − 500 ∗ 500 , 500 ∗ 500 ] [-500*500, 500*500] [500500,500500],所以我们可以直接开一个数组来用作桶,偏移一下范围。一个数加入桶时,记录这个数,最后通过这些记录的数清空桶。

5.边界处理
在计算矩阵和时,要记得矩阵边界是不包括的。

牛客10

J

1.递归解决子问题
如果要匹配节点 t 1 , t 2 t_1,t_2 t1,t2对应的树,可以考虑: t 1 t_1 t1中的儿子节点对应的子树,与 t 2 t_2 t2中的儿子节点对应的子树,进行匹配。

2.解决匹配问题
假设已经计算出(通过递归计算): t 1 t_1 t1的子树 s o n 1 son_1 son1,与 t 2 t_2 t2的子树 s o n 2 son_2 son2进行匹配需要的花费为 c o s t cost cost,那么可以建一条 s o n 1 son_1 son1 s o n 2 son_2 son2之间的边,边权为 c o s t cost cost。如果选中(匹配到)这条边,代表子树 s o n 1 son_1 son1与子树 s o n 2 son_2 son2进行匹配,花费为 c o s t cost cost。然后,我们对所有的 s o n 1 son_1 son1,与所有的 s o n 2 son_2 son2都建立边,形成图 G G G。接着,对这个图 G G G跑二分图最小权匹配,就可以得到最优的匹配方案了。

3.二分图最小权匹配
可以考虑:KM算法、费用流

4.细节
(1)树的大小要相同才能匹配
(2)树 t 1 t_1 t1和树 t 2 t_2 t2匹配的花费,除了子树匹配的花费(图 G G G)外,还有根节点 t 1 t_1 t1 t 2 t_2 t2进行匹配的花费。

杭电1

1005 (hdu 6755)

1.斐波那契数列通项公式
F n = 1 5 [ ( 1 + 5 2 ) n − ( 1 − 5 2 ) n ] F_n=\frac{1}{\sqrt{5}} [ (\frac{1+\sqrt{5}}{2})^n- (\frac{1-\sqrt{5}}{2})^n] Fn=5 1[(21+5 )n(215 )n]2. 5 \sqrt{5} 5 在模 1 e 9 + 9 1e9+9 1e9+9意义下的整数
因为: 38300801 6 2 ≡ 61699199 3 2 ≡ 5   ( m o d   1 e 9 + 9 ) 383008016^2≡616991993^2≡5 \ (mod \ 1e9+9) 383008016261699199325 (mod 1e9+9)
所以: 5 ≡ 383008016   ( m o d   1 e 9 + 9 ) \sqrt{5}≡383008016 \ (mod \ 1e9+9) 5 383008016 (mod 1e9+9)
5 ≡ 616991993   ( m o d   1 e 9 + 9 ) \sqrt{5}≡616991993 \ (mod \ 1e9+9) 5 616991993 (mod 1e9+9)
计算时选其中一个就可以了,无论选哪个都不影响最后的结果。

3.化简题目式子
设: a = 1 + 5 2 a=\frac{1+\sqrt{5}}{2} a=21+5 b = 1 − 5 2 b=\frac{1-\sqrt{5}}{2} b=215 c = 1 5 c=\frac{1}{\sqrt{5}} c=5 1,因此: F n = d ( a n − b n ) F_n=d(a^n-b^n) Fn=d(anbn)
所以:
∑ i = 0 N ( F C i ) K = ∑ i = 0 N [ d ( a C i − b C i ) ] K = d K ∑ i = 0 N ( a C i − b C i ) K \sum\limits_{i=0}^{N} (F_{Ci})^K=\sum\limits_{i=0}^{N}[d(a^{Ci}-b^{Ci})]^K=d^K\sum\limits_{i=0}^{N} (a^{Ci}-b^{Ci})^K i=0N(FCi)K=i=0N[d(aCibCi)]K=dKi=0N(aCibCi)K接着,我们对 ( a C i − b C i ) K (a^{Ci}-b^{Ci})^K (aCibCi)K进行二项式展开,得到其中一项是:
( − 1 ) m C K m ( a C i ) K − m ( b C i ) m = ( − 1 ) m C K m ( a C ( K − m ) ) i ( b C m ) i = ( − 1 ) m C K m ( a C ( K − m ) b C m ) i (-1)^mC^{m}_{K} (a^{Ci})^{K-m}(b^{Ci})^{m}=(-1)^mC^{m}_{K} (a^{C(K-m)})^i(b^{Cm})^i=(-1)^mC^{m}_{K} (a^{C(K-m)} b^{Cm})^i (1)mCKm(aCi)Km(bCi)m=(1)mCKm(aC(Km))i(bCm)i=(1)mCKm(aC(Km)bCm)i q m = a C ( K − m ) b C m q_m=a^{C(K-m)} b^{Cm} qm=aC(Km)bCm,得:
∑ i = 0 N ( − 1 ) m C K m ( a C ( K − m ) b C m ) i = ( − 1 ) m C K m ∑ i = 0 N q m i = ( − 1 ) m C K m q m N + 1 − 1 q m − 1 \sum\limits_{i=0}^{N} (-1)^mC^{m}_{K} (a^{C(K-m)} b^{Cm})^i=(-1)^mC^{m}_{K} \sum\limits_{i=0}^{N} q_m^i=(-1)^mC^{m}_{K} \frac{q^{N+1}_m-1}{q_m-1} i=0N(1)mCKm(aC(Km)bCm)i=(1)mCKmi=0Nqmi=(1)mCKmqm1qmN+11所以,答案就是把二项式的全部项加起来,即:
a n s = ∑ m = 0 K ( − 1 ) m C K m q m N + 1 − 1 q m − 1 ans=\sum\limits_{m=0}^{K} (-1)^mC^{m}_{K} \frac{q_m^{N+1}-1}{q_m-1} ans=m=0K(1)mCKmqm1qmN+11时间复杂度为: O ( K l o g N ) O(KlogN) O(KlogN)

4.计算优化
如果上述所有数都用快速幂求,大概率会超时。所以要尽可能少用快速幂,用递推优化。能递推优化计算的有: q m q_m qm q m N + 1 q_m^{N+1} qmN+1
q m = q m − 1 ∗ b c / a − c q_m=q_{m-1}*b^c/a^{-c} qm=qm1bc/ac q m N + 1 = q m − 1 N + 1 ∗ b c ( N + 1 ) / a − c ( N + 1 ) q^{N+1}_m=q^{N+1}_{m-1}*b^{c(N+1)}/a^{-c(N+1)} qmN+1=qm1N+1bc(N+1)/ac(N+1)
其中, b c , b c ( N + 1 ) b^c, b^{c(N+1)} bc,bc(N+1)可以先算出来; a − c a^{-c} ac的逆元, a − c ( N + 1 ) a^{-c(N+1)} ac(N+1)的逆元,也可以提前算出来。接着就可以用 O ( K ) O(K) O(K)的递推算出上述两个数。

1006 (hdu 6756)

1.性质
(1)图中度数超过 m \sqrt{m} m 的点的数量小于等于 m \sqrt{m} m
(2)一个点的 M E X MEX MEX的最大值是这个点的度数,所以大于等于度数的 A A A值都是可以忽略的。

2.求 M E X MEX MEX
对每个点都建立一个存值的“桶”数组 c n t cnt cnt,数组大小不超过这个点的度数。然后,再建立一个标记数组 v i s vis vis(标记数组不用真实创建,因为标记数组要用数据结构维护,这里只是为了方便叙述),大小与“桶数组”相等, v i s [ i ] = 1 vis[i]=1 vis[i]=1代表存在这个值,即 c n t [ i ] ≥ 1 cnt[i] \ge 1 cnt[i]1 v i s [ i ] = 0 vis[i]=0 vis[i]=0则相反。

(1)树状数组
用树状数组维护 v i s vis vis数组的前缀和,记为 p r e pre pre。假设 M E X = x MEX=x MEX=x,则有: p r e i = i + 1   ( i < x ) pre_i=i+1\ (i < x) prei=i+1 (i<x) p r e i ≠ i + 1   ( i ≥ x ) pre_i \ne i+1\ (i \ge x) prei=i+1 (ix),所以可以利用这个性质,对 M E X MEX MEX进行二分,然后通过查询前缀和来 c h e c k check check答案,时间复杂度为: O ( l o g n   l o g n ) O(logn \ logn) O(logn logn)

(2)分块
v i s vis vis数组进行分块,维护一个块内的和,块的大小为: u n i t = n unit = \sqrt{n} unit=n 。计算 M E X MEX MEX时,先从前往后扫描一个块,直到这个块的和不等于块的大小。这时,就找到这个块对应的 c n t cnt cnt数组的区域,从前往后扫描,直到 c n t i = 0 cnt_i=0 cnti=0,时间复杂度: O ( 2 n ) O(2\sqrt{n}) O(2n )

3.修改与查询
由1的性质,我们把度数小于等于 m \sqrt{m} m 的点称作:“小点”,把度数大于 m \sqrt{m} m 的点称作:“大点”。对于 “大点” ,需要额外维护 “旧值” 。

(1)对于修改操作:
对于小点,因为度数小于等于 m \sqrt{m} m ,所以暴力修改所有邻接点的 v i s vis vis数组和 c n t cnt cnt数组,然后修改自身的值。对于大点,则直接修改自身的值(注意不要修改 “旧值” )。

(2)对于查询操作:
对于所有点(无论是大点还是小点),思路是:先遍历相邻的 “大点” ,利用 “大点” 的值和 “旧值” ,修改自身的 v i s vis vis数组和 c n t cnt cnt数组。接着,利用修改完后的 v i s vis vis数组和 c n t cnt cnt数组进行查询。最后,再次遍历相邻的 “大点” ,把自身的 v i s vis vis数组和 c n t cnt cnt数组还原回去。

对于上述算法的时间复杂度,如果 v i s vis vis数组是用树状数组维护,则为 O ( q m   l o g n ) O(q\sqrt{m}\ logn) O(qm  logn);如果 v i s vis vis数组用的是分块维护,则为 O ( q ( m + n ) ) O(q(\sqrt{m}+\sqrt{n})) O(q(m +n ))。实测两种方法对于 o j oj oj上的数据似乎差别不大。

杭电2

1012 (hdu 6774)

1.性质
两个字符串的距离:两个字符串的长度 - 2 * 两个字符串的最长公共子序列。

2.预处理
A A A进行预处理,预处理出数组 f [ i ] [ c h ] f[i][ch] f[i][ch]:在 A [ i ] A[i] A[i]后第一个出现字符 c h ch ch的位置。

3.求最长公共子序列( L C S LCS LCS
(1) d p [ i ] [ j ] dp[i][j] dp[i][j]的意义:
下标 i i i B B B的前缀: B [ 1... i ] B[1...i] B[1...i]
下标 j j j B [ 1... i ] B[1...i] B[1...i] A [ l . . . r ] A[l...r] A[l...r] L C S LCS LCS长度
d p dp dp值:令 L C S LCS LCS成立的 A [ l . . . r ] A[l...r] A[l...r]的最短前缀长度
(2)转移方程:
d p [ i ] [ j ] = m i n { d p [ i − 1 ] [ j ] don’t select B[i] f [ l + d p [ i − 1 ] [ j − 1 ] ] [ B [ i ] ] − l + 1 select B[i] dp[i][j]=min \begin{cases} dp[i-1][j]& \text{don't select B[i]}\\ f[l+dp[i-1][j-1]][B[i]]-l+1& \text{select B[i]} \end{cases} dp[i][j]=min{dp[i1][j]f[l+dp[i1][j1]][B[i]]l+1don’t select B[i]select B[i]最后注意一下限制条件和初始化就可以了。

杭电5

1007 (hdu 6820)

1.连通图
如何“构成”连通图:在一个有根树中,一个连通图,可以从一个子树的根节点出发,然后一直连通到子树中的其他节点。所以,可以考虑统计子树内贡献的dp解决。

2.树型dp
(1)先考虑子树的根节点,与父节点相连,构成连通图的情况:
x x x为子树的根节点,则:

  • d p [ x ] [ 0 ] dp[x][0] dp[x][0]代表子树中,所有节点的儿子数量都小于等于 k − 1 k-1 k1(即所有节点度数小于等于 k k k)的子连通图最大边权和。
  • d p [ x ] [ 1 ] dp[x][1] dp[x][1]代表子树中,已经有1个节点的儿子数量大于 k − 1 k-1 k1(即已经有1个节点的度数大于 k k k)的子连通图最大边权和。

(自己的理解:因为连通图拆成子连通图,就只有两种状态:一是图中节点度数小于等于 k k k,另外是图中有 1 1 1个节点度数大于 k k k

(2)状态转移:
对于 d p [ x ] [ 0 ] dp[x][0] dp[x][0],只需要取 x x x的儿子中的前 k − 1 k-1 k1个最大 d p [ 0 ] dp[0] dp[0]值就可以了。
对于 d p [ x ] [ 1 ] dp[x][1] dp[x][1],有两种情况:

  • 子树中,根节点 x x x的儿子数量大于 k − 1 k-1 k1:直接选取所有儿子的 d p [ 0 ] dp[0] dp[0]
  • 子树中,非根节点的儿子数量大于 k − 1 k-1 k1:需要选取 x x x k − 2 k-2 k2个儿子的 d p [ 0 ] dp[0] dp[0]值,和1个儿子的 d p [ 1 ] dp[1] dp[1]值。这时,考虑枚举选哪个儿子的 d p [ 1 ] dp[1] dp[1]值。选完 d p [ 1 ] dp[1] dp[1]后,从剩下的儿子中,选前 k − 2 k-2 k2个最大 d p [ 0 ] dp[0] dp[0]值就可以了。

(3)如果有子树的根节点,不与父节点相连,这时只需要多选一个儿子就可以了,方法同上,然后把这个结果并入到最终答案里面(取最大值)。

杭电6

1005 (hdu 6831)

1.分解前缀
在前缀任意位置插入加号,乘号和括号,相当于插入加号和乘号,优先级任意。因为加号和乘号是二元运算符,而且前缀运算结果是由子区间得到的,所以考虑合并区间的dp解决。

2.区间dp
首先知道前缀最长长度肯定是不超过 n n n的。
d p [ l ] [ r ] [ v a l ] dp[l][r][val] dp[l][r][val]为区间 [ l , r ] [l, r] [l,r]是否可以构成值 v a l val val,则:
d p [ l ] [ m i d ] [ v a l 1 ] dp[l][mid][val_1] dp[l][mid][val1] d p [ m i d + 1 ] [ r ] [ v a l 2 ] dp[mid+1][r][val_2] dp[mid+1][r][val2]可以转移到 d p [ l ] [ r ] [ v a l 1 + v a l 2 ] dp[l][r][val_1+val_2] dp[l][r][val1+val2] d p [ l ] [ r ] [ v a l 1 ∗ v a l 2 ] dp[l][r][val_1*val_2] dp[l][r][val1val2](注意还有区间 [ l , r ] [l, r] [l,r]不插入运算符的情况),这时,只需要枚举区间长度 l e n len len,区间左端点 l l l,插入运算符的位置 m i d mid mid v a l 1 val_1 val1 v a l 2 val_2 val2,就可以把这个算出来了,时间复杂度为 O ( n 5 ) O(n^5) O(n5)

3.打表判断进行优化
虽然上述做法时间复杂度爆炸,但是通过打表一小段数据猜测(玄学猜测),最长长度应该不会太长。经过多次试验打表后(从小到大开始试),发现长度为 11 11 11时, n ≤ 5000 n \le 5000 n5000内,除了 3 3 3 7 7 7之外( 3 3 3 7 7 7无论长度多长,必定无解),全部都有解。这时,前缀最长长度就可以设置为 11 11 11,时间复杂度为 O ( 1 1 3 ∗ n 2 ) O(11^3*n^2) O(113n2)。因为题目有 30 30 30组样例,所以考虑预处理 n ≤ 5000 n \le 5000 n5000的答案,最后优化一下常数应该就行了(实测可以优化很大的常数)。

杭电8

1004 (hdu 6858)

1.题意
给出 m m m条边,有 q q q个询问,每次询问 [ l , r ]   ( 1 ≤ l ≤ r ≤ m ) [l,r] \ (1 \le l \le r\le m) [l,r] (1lrm)的边构成的图,是否有环。

2.尺取
R i R_i Ri为:以第 i i i边为开始,能构成环的最小右端点。只要求出 R i R_i Ri,每次询问时,只需要判断 r r r是否大于等于 R i R_i Ri,就知道是否有环了。而且还有一个性质: R i R_i Ri是非递减的,所以可以考虑用尺取法。

3.性质证明
假设 R i > R i + 1 R_i > R_{i+1} Ri>Ri+1,那么区间 [ i + 1 , R i + 1 ] [i+1, R_{i+1}] [i+1,Ri+1]的边构成的图肯定有环,即区间 [ i , R i + 1 ] [i, R_{i+1}] [i,Ri+1]的边构成的图也是有环的(增加一条边还是有环)。那么,在计算 R i R_i Ri的时候,因为是从左往右扫描的,所以肯定会先检测到 R i + 1 R_{i+1} Ri+1,即 R i = R i + 1 R_i=R_{i+1} Ri=Ri+1。所以: R i ≤ R i + 1 R_i \le R_{i+1} RiRi+1

4.动态树
在尺取的过程中,要判定有环,只需要判定 R i R_i Ri边的两个端点,是否连通,就可以了。要在添加边/删除边的同时,判定两个点是否连通,可以直接用动态树的模板解决。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值