2020多校补题

文章目录

    • 牛客1
      • A
      • H
      • I
    • 牛客2
      • A
      • B
      • H
    • 牛客3
      • D
      • E
      • F
    • 牛客9
      • J
    • 杭电1
      • 1005 (hdu 6755)
      • 1006 (hdu 6756)
    • 杭电2
      • 1012 (hdu 6774)

牛客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,k2k1,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被约矛盾,所以无解。

牛客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.边界处理
在计算矩阵和时,要记得矩阵边界是不包括的。

杭电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]最后注意一下限制条件和初始化就可以了。

你可能感兴趣的:(多校)