信友队 2024 暑假集训 · 贰
07/24
例题
-
-
很显然,先固定左端点,看哪个右端点好
-
也很显然,前 \(k\) 小直接贪心,堆维护
-
那么选掉一个 \((l, r)\) 后,不能重选如何处理?
-
把序列裂成两半即可。复杂度 \(O((n + k) \log n)\)
-
-
做过的题,跑路
-
其实就是以前一次模考的区间平行连边。
平行连边,最后把并查集的连通关系都下推掉即可。答案为 \(9 \times 10 ^ {连通块个数}\)
-
-
一棵树,\(n\) 个点,树上有 \(m\) 条公交路线,可以在路线上随便上下车,\(q\) 组询问,问最多换几次公交能从 \(u\) 走到 \(v\)。
-
先处理只坐一次公交最高到哪里,然后处理坐 \(2^k\) 次车能到的地方。
-
这样我们先把两个点跳到 \(\operatorname{LCA}\) 下面,看看能不能通过一次公交直接翻过 \(\operatorname{LCA}\)。判断方法可以二维数点 / 激活法。
-
07/26
two pointers & meet in the middle
前边的例题是不是太 simple 了
内容
双指针是一种通过一些性质(主要是单调性)优化暴力的算法。
方法
-
对撞指针
-
快慢指针
例题
-
好简单的双指针例题 1
-
也很简单的双指针例题 2
-
好像是链上找环状物,听懂了思想是有点像 Pollard-Rho,但还是没明白题目要干嘛
-
simple meet in the middle 例题
-
二分 + 双指针 check
话说这题的变形好像在去年 J 组洛谷模拟赛里有?
-
P1381
simple
-
每个数可以不选 / 选 \(a_i\) / 选 \(a_i!\),因此直接爆搜是 \(3^n\) 的,gg
因此 Meet in the middle
-
-
选任意个数,使之能化为和相等的两组,方案数
-
每个数 \(3\) 种状态,不选 / 第一组 / 第二组,\(3^{23}\) 炸了,因此 Meet in the middle,记录差值互相找
-
-
-
\(O(2^nm)\) 的算法显然
-
但是这里有一个似乎比较多的分析法:开店数量 \(\ge 2\) 的不超过 \(36/2=18\) 家,因此状压 \(2^{18}\) 即可。
-
07/27
zzy,最短路。
内容
-
普通最短路
-
差分约束
\(x_i - x_j = w_k\),连 \((i, j, -w_k)\) 和 \((j, i, w_k)\)。
例题
-
-
首先我自己胡了一种做法,看了下题解是对的:
每个点放堆里,堆里每个点按步跑 Dijkstra
-
然而更好的做法是只考虑前 \(k\) 小的边连接的点,是 \(O(m + k^3)\) 的。
当然,也可以 \(n\) 轮 Dijkstra 变成 \(m + k^2 \log k\) 的。
-
-
好像有重题吧,一个一个加点跑 Floyd 即可。
-
-
\(10^{18}\) 二进制下只有 \(60\) 来位,所以如果所有 \(a_i\) 在二进制下 \(1\) 的个数超过 \(180\),直接输出 \(3\)。
-
所以 \(n \le 180\) 时直接暴力,Floyd 跑完后枚举起点终点即可找到最小环。
-
这个分析有点像 Meet in the middle 时老师分享的那个 CCPC 女生场。
-
-
感觉好怪,这不就是把最短路 DAG 建出来再找最短路树吗?
-
-
我自己的口胡:肯定 DP 啊,\(K\) 这么小,大概就是 \(dp_{i, k}\) 表示比最短路多走多少的方案数。
如果 \(1 \sim N\) 的路径上 存在零环,那么就是 -1 了。
-
不过把一个点拆成 \(K\) 个实在是太妙了!
-
-
-
我的口胡:这不一眼线段树优化建图吗?(树套树)
好吧被卡空间 -
正解:改一下,利用 Dijkstra 只更新一个点一遍的性质,用线段树套
set
维护。
-
-
边可以重复走,因此只要有路径小于等于目标且与之与 \(2\) 同余即可。
所以记一下奇偶长度的最短路即可。
-
给定一张 \(n\) 个点的无向图,定义 \(dis(u, v, w)\) 表示 \(u - v\) 不经过点 \(w\) 的路径,如不连通则为 \(-1\)。求
\[\sum_{u = 1}^n\sum_{v = 1}^n\sum_{w = 1}^n dis(u, v, w) \]-
我的口胡:可以在 Floyd 时记录哪个点松弛了哪些点对,并记下次短路。然后先枚举 \(w\),再枚举被 \(w\) 松弛的最短路计算即可。\(O(n^3)\)。现在发现假了,因为节点是可以间接更新最短路的。 -
好神奇,听不懂。好像是什么时间线段树支持删除啊什么的。总之就是没听懂。抽象死了。
-
看了题解好像稍微懂了一点:\(dis(*,*,l, r)\) 表示不用 \([l, r]\) 时的全员最短路,加 \([l, mid]\) 处理 \(dis(*, *, mid + 1, r)\),加 \([mid + 1, r]\) 处理 \(dis(*, *, l, mid)\),\(l = r\) 时统计答案。
-
-
我的口胡:对每个节点记录它的前驱节点,然后……好像很简单了。
正解……没听。。。但我的口胡好像是对的。
-
求 \(\min |Z|\),满足 \(a_i \le x \le b_i, x \in Z\) 的数量 \(\ge c_i\)。
我的口胡:这不就是差分约束?区间转差分连连边。
正解:完了,又忘听了。。。看了下 POJ 上的题解,好像是对的
下午月赛晚上 ABC,题没时间做了,以后抽空再写吧。。。
07/28
Content
-
允许 \(K\) 次失配的匹配
二分
-
最长公共子串
- 把每个串的长为 \(k\) 的子串拉出来算哈希,看看有没有子串在每个字符串里都出现了,二分 \(k\)
例题
-
「NOI2016」优秀的拆分(\(N \le 2000\))
这题好像没花时间讲?
-
写过。
-
也写过。
-
怎么又写过了,是不是完全抄上学期的啊,不听了。
-
「POI2005」SZA-Template / Gym105114F
好吧,又是写过的,不过我觉得这次理解更透彻。
记下每个前缀最大能印到哪里(\(h\) 数组)。\(dp\) 记录答案。
07/29
可撤销并查集
把数组回滚即可,路径压缩不行,会被卡死。高大上是可持久化并查集,直白点就是个可持久化数组
实际上,均摊的复杂度都不能可持久化。
建堆
\(O(n)\),二叉堆能这么建是为了让底层更多的点少跑一点。
怎么不讲点高级的堆啊……
对顶堆
平板电视已经能跑了。。。时代变了。。。
set & map
用 s.rebgin()
获取最大值。
vi v(s.begin(), s.end())
insert
, erase
都有返回值。
什么???map
底层是 set
实现的???那我用什么 map
,再也不敢乱用了。
set
, map
, vector
的 swap
是 \(O(1)\) 的。
但经过 u 群的讨论(这是后话了),pbds 不是 \(O(1)\) 的。
例题
-
-
种类并查集
每个点分 \(a_i, b_i, c_i\),如果 \(u\) 吃 \(v\),则 \(a_u \Leftrightarrow b_v\)。
等价的东西之间并查集合并,如果发现 \(a_u \Leftrightarrow b_u \Leftrightarrow c_u\),那肯定假了
-
带权并查集
连的边有边权,表示 \(2\) 者的关系。但是关系要能合并。
-
-
\(n\) 个点,会连双向边,问 \(u_i, v_i\) 最早什么时候连通
哈哈哈,这是最小生成树,连边权值是操作是第几次,直接 \(u, v\) 路径最大值。
-
直接把整条路径合并了。来自老师的简短代码:
void modify(int u, int v) { u = find(u), v = find(v); while (u != v) { if (dep[u] < dep[v]) swap(u, v); merge(u, fa[u]); u = find(fa[u]); } }
-
一条待选边有用,当两点路径种有边断了。额,总之就是把链上全合并成尽可能小的待选边的值。
不过时代变了,好像可以用平板电视可并堆 + 树上差分了!
写了一下,并查集很简短
,哪里有紫 -
最贵的人尽量满足,并查集维护。
后来想了以下感觉和时光倒流有一点相似之处。
-
P1792「国集」种树 / 「JOISC2018 Day4」糖
一种是直接选
一种是把选过的 \(0101010 \dots 01010\) 反转了,把这种结构也看成点,值是反转后 - 当前
所以每次就是加上最大的点,如果相邻了可以合并一下成反转点,否则直接加。
难点在于,观察出这两类选糖的普遍方法。其实在遇到把糖换下来的时候我们就应思考反转这一点,因为换下来 / 放上去就是异或。
-
最长等差子序列(Leetcode1027)
要求复杂度 \(O(n^2)\),其实直接 dp 即可,至于值域,只要用
unordered_map
存一点东西即可,空间复杂度是 \(O(n^2)\) 的。- 然而 \(n = 10^4\) 很难卡,我们可以乱搞一下,如果 \(N\) 太大第二层循环只跑一半。😛
-
只要把要删掉的暴力删除即可,每个线段只被删一次,我用了 \(2\) 个
set
。啊,注意到线段两两不交,可以按照这个暴力,然后 \(1\) 个
set
维护连续段即可。set
也是维护连续段的利器。 -
是个超简单的诈骗题。对于这类题,一个数不会被操作很多次,可以看作常数,直接暴力即可。并查集维护不能修改连通块。
07/30
模拟赛。题好简单。rk. 1
学到了一点随机化技巧以及异或哈希这一算法。
08/01
内容
线段树标记永久化
常数小,不过通常不需要。
注意维护的 tag 要有交换律,比如线段树 2 就不可以。这样我们就不知道哪个 tag 在先了。
\(O(\log n)\) pushup
楼房重建等。那个黑题没听懂,好像也是。
势能线段树
就是区间开方之类的啊,其实不是很难。
例题
-
时代变了,其实 pbds 平衡树就够了可以动态开点 + sgt 上二分。好像就是主席树。
有 pbds 了还写什么 sgt -
线段树优化建图板子题
-
变成斜率,维护必须上升子序列长度。好难啊,不过代码似乎很好写的样子。现在懂了。
-
怎么是黑啊/kk
不听了!先放着!
08/02
概况
又是模拟赛。\(100 + 100 + 70 + 0 = 270, rk.3\)
这次在假做法上浪费 1.5h,默哀。
题目
A. hot 和 B. tunnel 都很蠢。C. tree 的前 \(50\) 是暴力 dp,\(20\) 分也好拿,这档部分分写掉还能顺便再拿 \(10\) 分。D. survive 有难度,但前 \(31\) 分很送。
理想分数 \(100 + 100 + 80 + [31, 62] = [\red311, \red342]\),是个很不错的分数了。
失误分析
-
又在假做法上浪费了大量时间。 tree 的最后一个假做法和暴力是违背的,但是编完假做法后完全没有冷静思考,直接耗尽了 survive 的时间。
-
完全没有思考 survive。看到数据范围和题目一脸懵逼,认为还要预判未来很不可做,完全没有思考可以一层一层记录状态,然后可以随便转移了。时光倒流也不是非常难想。
但关键还是没细想,并且在 tree 上浪费了时间。
改进
-
懂得取舍,不要因为一道题看起来可做 / 付出很多努力而死磕。
-
在一道题浪费的时间 \(\ge 30\min\) 时就应该打暴力 + 换题。因为你多半想不出剩下的部分。
-
不要觉得有完全不可做题,每题都投入一定的思考。
08/04
状压 dp。数位 dp。
内容
-
子集枚举复杂度: \(O(状压枚举集合层数 + 2)^n\)。
-
预处理
popcnt
:c[s] = c[s >> 1] + (s & 1)
。 -
生成树状压 dp
-
按层加点
-
选节点,合并子树
-
-
半行状压法
CF111C。
-
强连通图生成法
耳分解。一次一次加环。
例题
-
先瞎暴力,\(O(n^3 2^n)\)。
然后我们发现找有没有问题居然要 \(O(n)\),真烦。所以预处理优化掉是否非法。\(g(i, j, S)\) 表示 \(P_iP_j\) 是否经过 \(S\) 里的点。转移:\(k = lowbit(S), g(i, j, S) = g(i, j, S) \wedge [k \notin P_iP_j]\)。实际上,预处理直接处理两点直线交的点的集合即可。总复杂度 \(O(n^3 + n^2 2^n)\)。
据经验,预处理时用 \(lowbit\) 转移是常见方法。
-
结论:\(L = x + y\),这一范围内 dp 即可。
-
\(0 \sim 9\) 的数量记一下,模 \(m\) 的余数记一下。然后转移。
但这样很难写,记下使用了 \(n\) 的哪些位数即可。比较方便。确定一个填数的顺序,有利于转移。
-
我们按照先行后列的顺序枚举格子。然后我们只关心这个格子前 \(n\) 个。之后考虑被这个格子新覆盖的格子。
不过这个方法非常难写,因为要一堆分类讨论和位运算。懒得写了。
最优复杂度 \(O(nm2^{2m}) = O(nm4^m)\),懒一点可以写一个 \(O(nm6^m)\)。
-
按层加点。
-
Gym102759C Economic One-way Roads
很难。考虑建出一个强连通图,再在里面选两个作为新加的路径的端点。之后可以扩展。
老师:这题我看课件前都没见过。写课件的真是穷尽自己一生所学
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探