24-8-12 ~ 8-17 石门夏令营
posted on 2024-08-15 07:23:11 | under | source
记录下模拟赛。
DP 专场 1
过程:
因为是第一天要报到,所以拆成上下午两场各两题的形式。没啥影响,反而使得分高了。
上午:先看 A,有些蒙圈,装水时 lsy 说了一下,恍然大悟,原来是结论题,马上写完走了。
然后开 C,貌似有点想法,应该是建图然后计数,决定把它拆成奇偶两部,接着发现这个图有美好性质,好像可以做!难道这把要赢了?
折腾了一会死活过不去,打了个暴力对拍也没找出问题,最后发现是边连少了233。继续思考,最终是若干个残缺的网格图,在上面求独立集个数怎么会有多项式做法,难道是状压瞎搞?尝试拼一下,没写出来。
下午:开 B,一开始以为是神秘计数,后面发现结论,原来是朴素 dp,但是这题还要输出最小字典序诶,咋搞?以为是保留转移路径,取上一个状态中的最小的那个,后面发现不行,于是瞎搞了下,有些坎坷,所幸过了大样例。
开 D,没啥想法,打了个暴力,时间不多了就没有细想。最后给 B 加了个小补丁就溜了。
期望得分:100+40+100+15=255;最终得分:100+40+100+5=245。算是符合预期。
题解:
A:先化为数字序列,然后若两个序列长度、总和一样,那么就可以互相转化。证明,想象为水波,那么会存在一个稳定态,又因为操作可逆,所以能互相转化。
充分诠释“想象学竞赛”的魅力,所以要多 yy。
B:有显然的结论:假如操作了 \(m\) 对数,那么剩下的数必然是 \([2m+2,n]+x,x\in [1,2m+2]\)。然后 dp 并保留上一个字典序最小的最优状态,注意到这样正着 dp 求出的是倒着的字典序最小,于是倒着做 dp 就好了。
倒序 dp 的处理方式可以借鉴。
C:连边 \(u\to v\),然后统计独立集个数即可。对每个残缺的网格图统计,令 \(\times 2\) 的部分为行,\(\times 3\) 的部分为列,考虑状压 dp,\(f_{i,S}\) 表示前 \(i\) 行,第 \(i\) 行的选取方案为 \(S\) 时的总方案数,转移可以视为高维前缀和,提前处理即可。当然也可以写成轮廓线 dp。单个网格图复杂度 \(O(\log_2N\log_3N\times 2^{\log_3N})\),\(N\) 是值域。
最后,为啥多个网格图复杂度正确?不妨对每一行单独计算复杂度,假设这一行的开头是 \(x\),那么复杂度是 \(O(\log_3\frac Nx\times 2^{\log_3\frac Nx})\)。
考虑 \(\log_3 \frac Nx\) 项,可以发现取值为若干段区间,即 \(\frac Nx=[1,2],[3,8],[9,26]\dots\),考虑区间 \(j\in [3^{i},3^{i+1}-1]\),\(\log_3 j=i\),然后取值在区间内的 \(x\) 个数约为 \(\frac {N}{3^{i+1}}-\frac{N}{3^i}\),可以放缩为 \(\frac {N}{3^{i+1}}\);它们的贡献为 \(i2^i\),放缩为 \(i3^i\),所以区间贡献为 \(O(i3^i\times \frac{N}{3^{i+1}})=O(iN)\)。
\(i\) 最大为 \(O(\log_3 N)\),所以总复杂度为 \(O(N\log_3 N)\),而且这是个非常松的上界,完全可以通过。
D:先只考虑偶数。要计数,先判定,构造单射,令 \(b_i=a_{p_i}\)。起始情况选取两个相等的数填到 \(b_1,b_n\),然后假设已经确定 \(b_1\dots b_{i-1},b_{n-i+2}\dots b_n\),设 \(S\) 为或之和,那么选取的两个数 \(x,y\) 合法,当且仅当 \(S\) 为 \(0\) 的那些位上 \(x,y\) 相等。
这相当于填写一个回文序列,只不过每次忽略掉一些位。注意一下,假如某一次填写有多种选择,随便选一种即可,因为其它选择之后也必然合法。
然后考虑不完美序列与完美序列的联系,可以发现,两者互为补集,同时不完美序列由 \([1,i],[i+1,n-i],[n-i+1,n]\) 构成,其中 \([1,i]+[n-i+1,n]\) 是完美序列,\([i+1,n-i]\) 由忽略某些位后互不相等的元素构成。
于是设计状态 \(f_{i,j}\),表示已经填写 \(b_1\dots b_i,b_{n-i+1}\dots b_n\),恰好涉及 \(j\) 位,对应的 \(a_1\dots a_n\) 的不同方案数。
\(b\to a\) 并不构成单射,所以要着重关注去重。
然后设计辅助状态 \(all_{i,j},dif_{i,j}\),分别表示总集、互不相等方案数。不难容斥得出。
然后有转移:
解释:\(i,j\) 不能取到 \(n,k\) 否则会出错。组合数在 \(a\) 中选择若干位置和二进制位作为完美序列部分,总集减 \(f\) 是求这些位置的完美序列,最后是互不相等部分,二次方部分是为互不相等部分的数确定被忽略的二进制位的取值。
看起来很完美,不是吗?考察一下这样做会不会算重(显然不会算少)。考虑完美序列部分与互不相等部分,我们必须满足两者没有相同的元素,才能使用 \({n\choose i}\) 将两者组合为一体,否则映射到 \(a\) 上就会算重。
记完美序列部分设计到的位为本原位,其余的是新增位。
由于互不相等部分的新增位有值,而完美序列部分此处无值,所以不会算重。但是!这题毒瘤的地方来了,\(a\) 可以填 \(0\)!所以就会导致两个部分有交于是算重。
怎样解决呢?观察到互不相等部分至多有一个 \(0\),这启示我们按是否有 \(0\) 分类转移。
一种好写的解决方案是修改完美序列的定义。若长度为偶数,保留原有定义。若为奇数,就让它必须存在一个 \(0\),且除掉一个 \(0\) 后为完美序列(是题面的定义)。同理能推出 \(f\) 的定义。
然后让 \(dif\) 不能填 \(0\),这样转移枚举的两部分不可能相交了。
然后解释下修改后的转移:
-
偶数长度:假如枚举的两部分为偶数,那么就能求出不存在 \(0\) 的方案;否则就是求有 \(0\) 方案,可以理解为让奇完美序列保留的那个 \(0\) 加到互不相等序列中(显然加完后依旧互不相等)。
-
奇数长度:此时 \(f\) 的定义为互不相等部分长度大于 \(1\)(即题面定义的不完美序列)或互不相等部分长度为 \(1\) 且不为 \(0\)。那么当枚举的互不相等部分大于 \(1\) 时就是对应了前者,否则对应了后者。
这样就不会算重了!更好的是,转移没有发生变化,仅仅是多考虑了奇数并修改 \(dif\) 的定义。
然后答案是 \(\sum\limits_{i=0}^k {k\choose i}f_{n,i}\)。
假如 \(n\) 为奇数怎么办?根据题面定义,那么 \(f_{n,i}\) 不应该包含“互不相等部分长度为 \(1\) 且不为 \(0\)” 这部分,因为剩下的一个元素想填啥就填啥。所以此时不要转移即可。即 \(i=n-1\) 且 \(n\) 为奇数时不转移。
总结
- 提升直觉和抽象化能力。
- 不要直接否认做法。
- 计数 dp 注意去重和映射关系,D 题避免去重的思路值得借鉴。
课后练习
E:考虑建模,若 \(u\) 工厂生产的材料用于修建 \(v\) 工厂,则建边 \(u\to v\)。那么直接状压 dp 即可,\(O(n3^n)\)。
F:小清新的好题。
- 拆分限制:一个自然的想法是,\(\max\limits_{l\le i\le r} a_i=mx\) 等价于 \(\forall l\le i\le r, a_i\le mx\) 且 \(\exist a_i=mx\)。
- 观察性质:简单手玩得知,若区间 \([l_1,r_1],[l_2,r_2]\) 有交,且 \(mx_1\ne mx_2\)。不妨令 \(mx_1<mx_2,l_2\le r_1\),那么便有可以把交集划分给 \([l_1,r_1]\)。以此类推,两个限制不同的区间无交。
- 观察性质(另一种方法):注意到拆分的限制中,只有前者是好做的:令 \(mi_i\) 为 \(a_i\) 最大取值,即跨过 \(i\) 的区间的限制之最小值,\(ans=\prod mi\)。然后发现 \(mi\) 不一样的部分不会互相影响,容易反证。感觉没有第一种方法来的自然。
- 大力 dp:所以考虑 \(mi_i\) 相同的部分,不同部分方案数相乘即可。这等价于一种问题,有若干点可以染色为黑或白,然后每个限制形同一个区间内至少一个黑点,容易 dp。
- 注意细节,特判无解。
DP 专场 2
过程
先开 A,woc 这不是原吗?由于之前太菜完全不会,所以印象深刻,马上秒了。看 B,有点吓人啊,不过上个厕所后突然会了,但不会优化,悲。看 C,这题面都给出了暴力 dp 了丫233,也是完全不知道怎么优化呢。最后思考 D,马上得出个暴搜,遂敲之。最后就在卡常、磕 D、摸鱼了。
期望得分:100+80+40+30=250;实际得分:100+100+60+30=290。
卡常神力。
题解
A:淼。
B:显然要构建出哈夫曼树,然后考虑递归构建,由于字典序是从高位开始比较的,所以就是划分子树嘛,然后得到了 \(O(n^3k)\) 做法。状态是 \(f_{l,r,k}\) 表示 \([l,r]\) 划分为 \(k\) 个区间的最小花费。
注意到 \(k\to \{k-1,1\}\) 是低效的,不妨变成 \(k\to \{\frac k2,k-\frac k2\}\),假设一开始是 \(K\),那么我们有结论:这样的不同数值数量为 \(O(\log K)\) 级别,于是优化到 \(O(n^3\log k)\)。当然,可能某个区间无法划分为 \(K\) 个,所以 \(f_{i,j,k}\) 应当为划分至多 \(k\) 个区间。
C:厉害题。暴力 dp 是容易的,\(f_{i,j,x,y}\) 表示行 \([i,j]\)、列 \([x,y]\) 的最小代价,\(O(n^5)\)。优化从两个角度思考:状态、转移。
状态:首先观察大样例,发现答案是很小的,可以证明,\(h*w\) 的矩阵,答案至多 \(\lceil\log h\rceil + \lceil\log w\rceil\)。证明首先考虑一行,可以类似线段树进行划分,深度最多为 \(\lceil\log h\rceil\)。然后将所有行视为整体再划分,同上。
于是可以对 \(f\) 换量,\(f_{i,j,x,k}\) 表示行 \([i,j]\)、列从 \(x\) 开始,且代价 \(\le k\) 时,最多到哪个列。直接转移,瓶颈在枚举划分行,即 \(\min(f_{i,p,x,k-1},f_{p+1,j,x,k-1})\to f_{i,j,x,k}\)。复杂度 \(O(n^4\log n)\)。
转移:首先注意到 \(i,x,k\) 固定,\(j\) 越大,\(f\) 越小。所以我们考虑决策点(划分行)\(u>v\),然后考虑其对应函数 \(g\),可以发现,一开始划分的上半部分取到 \(\min\),会有 \(g(u)<g(v)\),但是上半部分是固定的、下半部分是移动的,所以随着 \(j\) 增大,下半部分逐渐取到 \(\min\)(而且一定是 \(v\) 的下半部分先取到),那么 \(g(u)>g(v)\)。
也就是满足决策单调性,优化为 \(O(n^3\log n)\)。
D:脑电波题。显然每个僵尸只会被相邻的土豆雷炸死,只会被一个土豆雷炸死的僵尸无需讨论。于是考虑将僵尸描述为 \((x,y)\),每次等价于让所有 \(x-1\) 或 \(y-1\)。
不妨放在坐标系上,这样等价于移动坐标系而固定点(建模转化)。显然只需要确定被左边炸死的僵尸,即先碰到 \(x\) 轴的点。由于在一个点被选择了,那么其右下方的点也一定被选择,然后没有其它限制了(观察限制)。
那么问题变为在该限制下选点,显然,我们只需要考虑不被其它点覆盖的点(观察特征),那么等价于选二维上升子序列,\(O(n\log n)\) 解决。
总结
- 某些区间划分问题可以考虑倍增优化。
- 实在不会了可以考虑从状态、转移两方面入手,不要没有确定的目标。
- 观察大样例。
- 多动脑筋多转化,但不要复杂化问题而适得其反。
练习
E:赤果果的单调队列优化 dp。
F:非常好计数题,使我旋转。
-
简化限制:插入 \(pos,x\) 合法,需满足 \(\exist i<m,x=a_{pos+1}=\dots =a_i,a_i>a_{i+1}\),或是 \(x=a_{pos+1}=\dots=a_m\)。
-
转化限制:将其视作若干数字段,要么新建一个数字段;要么找到一个数字段 \(A\) 满足后面没有段或后面的段较小,然后将 \(A\) 左扩大一位。为了方便,不妨让 \(x\) 接在数字段右边,这样无需考虑“跳过相同数字”。
-
检查映射:操作序列 \(\to\) 结果序列为单射,启示我们对结果序列计算操作序列。
-
最小值分治:上述限制是否有些类似“合并类 dp”?于是考虑数值。记结果序列的最小值(最靠左的)为 \(a_{mi}\),左半部分记为 \(A\),右边记为 \(B\)。
-
观察限制:容易发现,\(a_{mi}\) 必须比 \(B\) 先插入;其次,\(a_{mi},B\) 的填写情况对 \(A\) 无影响(假如反过来也显然成立)。于是构成子结构了,可以 dp。
-
设计 dp:记 \(f_{n,mi}\) 表示长度为 \(n\) 的、最小值恰为 \(mi\) 的操作序列方案,\(g_{n,mi}\) 为 \(f\) 的后缀和。转移如下:
- 细节:处理好 \(n=0\) 的情况。
线段树专场 1
过程
看 T1,马上整出做法,但是调了会儿。看 T2,被吓到了,嘎嘎转化,结果中途推错好几次,整成了一个看起来还行的式子,不过不知道怎么直接算,找了找性质,于是有个随机数据下还行的做法,敲完赶紧跑了。还剩 1h 左右,听李遂说 T4 是板,但是我不太会线段树合并,所以先敲完 T3 暴力。最后写了下 T4 朴素 dp 和部分分,遗憾离场。
期望得分:100+[60,80]+20+44=[224,244];实际得分:100+45+20+44=209。
题解
A:HH 的项链加强版,没啥好说。
B:显然对排列插排的次数为逆序对数量,将其视为二维数点,那么求一个矩阵,其左上、右下有点,最大化矩阵点数。
容易发现,若 \((a,b),(x,y)\),满足 \(a>x,b<y\),那么 \((a,b)\) 当矩阵右下更优,同理有左上的结论。那么先预处理出 \(L,R\) 数组为待选的左上、右下点。
然后有决策单调性,若对 \(R_i\) 有 \(x<y\) 且 \(L_y\) 更优,那么往后 \(L_x\) 必然劣于 \(L_y\),容易证明:右下端点右移,可以发现 \(L_x\) 的减少区域不少于 \(L_y\),\(L_x\) 的增加区域不多于 \(L_y\)。
可持久化线段树求矩阵点数,于是 \(O(n\log^2 n)\) 解决。
C:讨论 \(dir=1\) 即可,其它情况可以归化为 \(dir=1\)。
然后处理思路是“拼图”,将其化为若干好求的规则图形。可以看成平行四边形减去两个梯形,斜线用 \(x+y\) 描述即可,复杂度瓶颈在梯形,要用二维描述。
总复杂度 \(O(q\log^2 n)\),常数较大。
D:线段树合并优化 dp 板题。首先我们有朴素 dp,将其改写一下便于优化,尽量单独拆为加法、取最值等。
记 \(f_{u,k}\) 表示考虑 \(u\) 子树内果实的选取,且天数在 \(k\) 天以内最大值是多少。
假如不取 \(u\):\(f_{u,i}\gets \sum f_{v,i}\);假如取:\(\forall i\ge day_u,f_{u,i}\gets w_u+\sum f_{v,day_u}\)。
第一种转移是直接合并,第二种转移是区间取 \(\max\)。用线段树合并维护,观察到 \(f\) 取值为若干连续段,每次取 \(\max\) 至多让连续段数量 \(+1\)。
所以维护这些连续段,具体而言,将取 \(\max\) 转化为赋值,使用标记永久化即可。这样只建 \(f\) 上产生变化的点就好了。复杂度 \(O(n\log n)\)。
当然可以用 map 直接维护拐点,并启发式合并,维护的是差分,挺精简巧妙的。复杂度 \(O(n\log^2 n)\)。
线段树专场 2
题解
A:淼,对每种字母单独处理,变成区间赋值。复杂度 \(O(n\log n)\) 带 \(26\) 大常数。
B:求所有区间的价值和然后乘上概率即可。
拆贡献,求每种颜色的贡献,发现正着做要求的是类似“跨过一个区间的方案数”,不好搞。注意到所有颜色总价值是 \(n(n-k+1)\),于是正难则反,求不被贡献的区间。
考虑颜色 \(col\),得到该颜色出现的所有位置 \(p_1\dots p_m\),那么 \(cnt=\sum\limits_{i=1}^m \max(p_i-p_{i-1}-k,0)\)。\(res=\sum\limits cnt\)。
干脆把所有颜色放一起考虑,记 \(c_i\) 为 \(i\) 左边最近的满足 \(a_j=a_i\) 的 \(i-j\),set 维护。那么 \(res=\sum \max(p_i-p_{i-1}-k,0)\)。不妨变为 \(res=nk-\sum\max(p_i-p_{i-1},k)\),两个树状数组维护即可。
注意特殊处理每种颜色末尾空白段(即 \(n+1-p_m\))。复杂度 \(O(n\log n)\)。
C:注意到每种旅团可以用等差数列 \((beg,d)\) 描述,操作 \(1,2\) 是容易用线段树维护的。
具体而言,加入无限旅团,则全局 \(beg,d\) 乘 \(2\);加入有限旅团 \(k\),则全局 \(beg+k\)。\(O(n\log n)\)。
考虑操作 \(3\),注意到往左至多经过 \(\log K\) 个无限旅团,此考虑此范围内的旅团即可。同时,对于每段连续的有限旅团,其 \(d\) 相等,大力维护即可。
但是这太不漂亮了,操作 \(3\) 实质上是操作 \(2\) 倒过来,那么不妨正难则反,按时间顺序将旅团删除,看第一次是被哪个旅团删除。
所以现将操作离线,倒着扫一遍。每次维护待选操作 \(3\) 集合(注意编号要实时更新)。现在考虑一次操作 \(1\),假如是无限旅团,那么所有奇数编号的都会被选中,然后让偶数编号除 \(2\);假如是有限旅团,那么 \([0,k-1]\) 被选中,并将其余编号减 \(k\)。
如何维护?可以用两个 set 分别维护奇数和偶数集合,并维护全局减标记,注意更新奇偶关系。除 \(2\) 暴力做即可,因为一个点至多 \(\log K\) 次就变成 \(0\),注意对 \(0\) 特殊处理不然会退化。
总复杂度 \(O(n\log n+n\log K)\)。
D:题意人话版:维护一个记事本。
注意到每种按键在不同情况下有不同效果,所以第一步是“模式识别”:
-
ctrl 判定:看左走第一次遇到的是“松开 ctrl”还是“按下 ctrl”。我们发现,对于区间查询,只要找到最左边的 ctrl 键位置 \(pos\),那么 \([l,pos-1]\) 只会增加前缀长度,\([pos,r]\) 的判定和全局一样。
-
全选判定:首先,对于已按下 ctrl 的 A,那么变为全选状态;然后若有输入操作则会取消全选,即单个字符或 ctrl+V。同上,对于查区间可以找到第一个 ctrl+A 的位置 \(pos2\),显然有 \(pos<pos2\),\([pos,pos2-1]\) 都是没有全选的操作,\([pos2,r]\) 的处理和全局完全一致。
然后直接进行操作即可,记 \(len,cpy\) 为记事本文本长度、剪切板文本长度。
- 单个字符输入:全选时,\(len\gets 1\);否则 \(len+1\)。
- ctrl+C:全选时才能有效果,\(cpy\gets len\)。
- ctrl+V:全选时:\(len\to cpy\);否则 \(len+cpy\)。
这不难用矩阵描述。根据先前讨论,我们预处理一颗强行钦定非全选的线段树 \(t1\)、一颗对于全局的线段树 \(t2\),维护矩阵乘积即可。复杂度 \(O(n\log n)\) 带 \(3^3\) 的常数。
树上问题专场 1
树上问题专场 2
过程
奇妙场,快速切 T1,想 T2,想了好久终于得到了一种将树剖优化成 \(O(n\log n)\) 的做法,很快码完了。最后打了打部分分。很奇妙,原本排在老后面了,结果重测后居然 rk1,骄傲。
题解
A:单点出发遍历整棵树是经典问题,答案即为 \(2(n-1)-\max dis_{rot\to i}\)。对于红蓝两点重合直接这样做即可。
假如不重合,那么一个直接的想法是让两点沿树上路径相向而行,走到中点 \(mid\) 重合。反证法可证:假如走到不是中点的点 \(y\),多走 \(dis_{mid\to y}\),最长链少了 \(dis_{mid\to y}\),一定不优。
假如路径长度为奇数,也就是说无法完全重合——其实没有影响,可以理解为每次红点在蓝点相邻出,下一次蓝走到红位置即可。
B:好题,题意等价于删去路径、查询一个点所在连通块。
套路:时光倒流,删边变为加边。那么用并查集维护是容易的。
现在唯一问题是怎么不让边被重复删去,找到其第一次被删去的时间即可。考虑树上并查集,用 \(f_u\) 表示往上找到第一个满足父边未被删去的祖先,那么每次向上跳 \(f_u\) 即可,复杂度均摊正确。
C:考虑枚举最终直径的中点 \(x\),二分答案其半径 \(d\),那么求出以其为根、所有叶子深度到达 \(d\) 时的操作数,满足 \(\ge k\) 即可。所有答案求 \(\min\) 即可,正确性显然:一条直径对答案的最小贡献一定在其中点上取到。
我们不可能枚举所有点,所以直接二分,考虑一个点 \(x\),操作数是 \(|leaf|\times mid - \sum\limits_{j\in leaf} dep_j\),同时必须有 \(\max\limits_{j\in leaf} dep_j \le mid\)。
由于以叶子为根显然不优,所以 \(leaf\) 集合是固定的,于是最小化 \(\sum dep\) 即可。可以换根 \(\rm dp\),然后扫一遍前缀最小值。
但是注意,直径中点可以在边上,怎么处理?不妨将边 \((u,v)\) 拆成 \((u,y),(y,v)\),然后变为枚举点。但是现在每条边长度为 \(\frac 12\),一次延伸操作对应而来是对同一叶子新增两条边。对于深度为 \(h\) 的叶子,能进行的新增的边数为 \(d-h-[d\bmod 2= h\bmod 2]\),于是要分奇偶讨论。
最后解决一个小问题:直径中点会不在原树上吗。考虑上述二分的方案构造,我们先让所有较小深度的叶子延伸,直到所有叶子深度一致再一起移动。稍微 yy 一下,直径的中点只会在原树上移动。
复杂度 \(O(n+Q\log K)\)。
D:还没写。

浙公网安备 33010602011771号