2024.11.[~, 28]训练记录
好,今天是noip2024前最后一次模拟。
但是我参加不了noip。
还是认真参加了模拟赛。
自主复习就写训练记录吧。落下很多天了。
今天的题疑似有点难订正了。那就先写今天的。
11.28noip模拟
今天的考试时间为了全真对标特意推迟了半个小时,写到最后还是有点困了。
毕竟平常一点钟睡午觉。
T1
感觉这道在这两天的 T1 里面算难的。大概做了两个小时。
noip 难度,现在全力挑战的区间就是 T1T2。考试的时候 T2 能做出来就会很高兴了。
题意转化一下大概就是求方格中有多少不包含障碍点的矩形。
\(n^4\) 是简单做法。但是 \(n^3\) 才有正常分。
先思考 \(n^3\) 的做法:
为了不算重,很常规的想法是考虑以某个点为左上/右下的矩形个数,今天使用的是左上。
一开始想到的是用数据结构维护二维前缀和的式子。写出来会发现式子长的非常难受。
\(s[i][j] - s[i][y - 1] - s[x - 1][j] + s[x][y]\)。
怎么移项中间的那两项好像都没法弄好看来。
这里被困住了很久。
结果换了全新思路。
最近的很多题好像都是刻画答案的形式之后去考虑怎么弄出那样的形式。
所以这种思考方式现在用的比较多。可能属于 noip 难度思维题的共性 trick(?)
发现一个点为左上的矩形,右下的点会大概排成一个阶梯的样子:
所以就想到一个 三方log 的做法。
对于每一个点 \((i, j)\) 考虑顶边为 \([j, k]\) 的矩形个数。
知道了顶边就只要往下二分一个长度就能知道矩形个数了。
最后这个做法没有写出来。因为这个和正解其实很像,直接想到了正解。
仍然是对于 \((i, j)\),考虑顶边为 \([j, k]\) 的矩形个数。但是从右往左做。
因为要优化掉一个 \(n\),所以我会考虑这个点的答案以复用其他点答案的方式得到。
这里就考虑了右边的点。
对于每一个右边的点的答案,决定它能不能成为当前点答案的唯一局限是:
使 \((i, j)\) 这个点往下延伸到这个答案需要的长度,会不会被挡住。
也就是,设右边的答案是 \((x, y)\),\((i, j)\) 到 \((x, j)\) 这个宽度为 \(1\) 的矩形中不能有障碍。
所以,对于每一个右边的答案,它能成为当前点的答案,当且仅当它的“深度”小于等于 \((i, j)\) 正下方的第一个障碍物。
这里做法就挺明确了。从右往左,答案的深度只能单调递增。
维护右边的每个点往下可以作为当前点答案的深度。每次对于当前点最浅障碍深度取 \(min\),求和。就能得到最后的答案。
这个取 \(min\) 考场想用线段树维护,后来发现其实就是一个单调栈。栈里面维护 \((\) 一个深度 \(x\),这一行答案深度是 \(x\) 的位置个数 \()\)。 \(x\) 从右往左单调递增维护就做完了。
这题虽然想的时间比较久,但是好在最后没有烂尾,一步一步想的过程都很明确。
希望在这种题上思维得到锻炼,今天花的时间还是太多了。一定程度上影响到了 T3T4 的暴力分变少。
下次碰到矩形统计题目,单调栈要放到常用算法中,这才能是经验丰富的选手。
T2
想了一些奇怪的假作法都寄了之后发现:
时限是4秒
注意到 \(\log {3*10^6} \approx 21\)。
\(21 * 10^7 = 2.1 * 10^8 < 4 * 10^8\)。
所以二分矩形的长度直接跑 bfs 就过了。
bfs 稍微有点细节吧。
对于一个边长为 \(len\) 的正方形跑四连通,可以只跑左上角。
用各种二维前缀和维护可行性,判下一步能不能走什么的。
跑的时候只打左上点的标记。
最后判断一个点在过程中有没有被覆盖过只要查以这个点为右下角的正方形中有没有标记。
挺好想的,比第一题简单吧。
常数不大,O2 下大样例跑了 \(3.22\) 秒。
查询cpu主频的常数是 CLOCKS_PER_SEC
。一些大神的缺省源里有。
下课了先去乒。
鲜花:抢到台球桌了,赢。
11.27noip模拟赛
T1
容易发现性质:两位及以上的数的答案就是每位答案之积。
考试的时候发现了这个就过了,\(f[0, 9]\) 直接手推什么的预处理,样例给了一部分,还可以用性质反推之类的。
这个性质是因为,\(a\)、\(b\) 相加时不能存在进位。否则不可能满足 \(f(a) + f(b) = f(c)\)。
T2
注意到我 T2 从 8:30 开到 12:20,绷不住了。
幸好最后调对了。
思路还是很好想的,大概半个小时就做出来了。
先记录一下我的思路吧,实现难度略高。
首先考虑,区间不会相交,只有相离和包含这两种关系这个性质怎么使用,非常关键。
意思就是,将区间全部排到轴上时,每一个相离的大区间内包含的小区间形成一个树形结构。
那么可以把这个树建出来。
具体来说,将区间按照 \(l\) 排序,\(l\) 相同时按照长度降序。
那么对于当前区间 \([l, r]\),只有满足 \(l_i <= l, r_i >= r\) 的长度最小的区间可以成为它的父亲。
注意到这是个二维偏序,可以遍历时把 \((len, id)\) 插到权值树状数组的 \(r\) 位置上。查询的时候只需要后缀 \(pair\) 最小值找到编号。
这样就建完森林了。
现在考虑怎么处理操作:
可以发现,一个区间能有答案,它的所有子区间必须先有过答案。
即树上,任意一个子节点的答案小于等于它的父亲的答案。
所以可以先处理完所有子节点,再处理父亲。开始处理父亲时将子节点维护的信息和父亲合并,将子节点删除后就将这个父亲打落成叶子了。
所以我们在处理操作时,只需要找到包含这个操作的叶子节点。在那个区间中进行信息的修改。
然后考虑怎么维护信息:
对于一个区间,我们维护一个 set。
将区间内的所有数插入 set 中后,如果 set 的大小和区间长度相同。那么这个区间内的数就两两不同。
于是我们得到了判断区间合法的方式。
使用 set 将子节点的信息给到父节点可以使用启发式合并。
现在唯一难维护的点就是我们单点修改时,修改的位置上原来的数是否需要在set中删除。
当需要删除时,这个区间中,原来的数出现的次数正好是一次。
所以可以再开 \(V\) 个 set,保存每个数出现的位置。
修改时在这些 set 中找到原来的颜色出现的位置,然后看左边/右边的这个颜色是不是都在区间外。
如果区间内还有这个颜色就直接将新颜色插入区间的 set,同时修改位置。
如果没有了,就多一步,在区间的 set 中删掉原来的颜色。
一些细节:
叶子区间有答案之后,不能直接和父节点合并。
有答案之后应当继续维护内容,直到父节点的每一个儿子都有过答案,再将所有儿子合并。
否则一开始合并上去的内容就是过时的,在所有儿子都合并之前对这段区间的修改无法反映到父亲上。
对于一个父亲,它的儿子不一定连续。
值域中两个儿子的空隙直接暴力遍历后插入,均摊 \(O(n)\)。
方法大概就是这样。复杂度,set和启发式各有一个 \(log\),所以总的是 \(O(n \log ^ 2{n})\)。
T4
点有全局的优先度。遵循以下规律排序。
- \(a[i] <= b[i]\) 时,按照 \(a[i]\) 从小到大排序。
- \(a[i] > b[i]\) 时,按照 \(b[i]\) 从大到小排序。
- \(a[i] <= b[i]\) 的情况排在 \(a[i] > b[i]\) 的情况前面。
这三个里面应该只有第二个比较难想。
考虑从最后的情况往前推,那么最后的 \(b\) 要减掉。这样最后的 \(b\) 最小就可以贪心的使最小值最大。
正过来看就是 \(b\) 倒序排。
有了这个排序方案,我们可以看到全局的最优点。
因为全局最优,所以走到它的父亲之后一定马上走到它。
可以用类似算阶上一道题的方法,将它直接和父亲合并,赋上新的权值。加入最优解的选择。
新的权值如何给:只要从原点直接连到最小值,再连回最终值就好。
考虑做父亲再做最优点的过程,你身上的值先下降再上升再下降再上升。我们就是把这个过程捋平。
就做好了。
补训练记录很痛苦吧,再前面的感受就有点忘了。
有些记录还烂尾了。
写一下印象深刻的题。
11.25 T4
这场的 T2 是超绝贪心,没想出来。
这很难吧。
然后看 T4。
考虑容斥,减去所有包含连续数的路径。
依次考虑每一对连续的数 \((u, v)\)。
如果 \(u\)、\(v\) 没有祖先关系。那么两个端点分别在 \(u\)、\(v\) 子树内的路径是不合法的。
如果 \(u\) 是 \(v\) 的祖先,那么如果一个端点在 \(v\) 的子树内,另一个端点在 ** \(u\) 在 \(v\) 方向的儿子的反子树** 内的路径是不合法的。
注意到不合法的路径端点都和子树有关,于是把编号拍到 dfn 上,就变成区间处理问题。
设一条路径的端点是 \((x, y)\),把 \((x, y)\) 视作平面直角坐标系上的一个点。
那么每一次会使坐标系中的一个矩形不合法。
两个子树形似:
有反子树的情况形似:
因为 \((y, x)\) 也不合法,所以每个矩形需要对称。
扫描线求矩形面积并即可。
这个板好像这两天挺常用的。