每道题口胡一句话。
9.1
今天怎么 6 题,说是手速场,我咋一道都不会啊。
T1
差分。
T2
首先一定可以得到每条边只能被覆盖 \(0\) 次或 \(1\) 次。然后做树形 DP,记录 \(f_0(u),f_1(u)\) 分别表示 \(u\) 子树是否向上连边的最小代价(次数和边数)。用插头的形式表示次数,即在一次操作的两端的边改变插头状态。转移时合并各儿子,讨论 \(0/1\) 状态之间的转化。
T3
不互质的数一定要在一块,并查集一下,\(1\) 特殊处理,答案是 \(2\) 的幂。
T4
在 01-trie 上 dfs,记录合法点集,转移用 \(\texttt{std::bitset<>}\) 就过了。
T5
考虑 DP \(F_i(S)\) 表示到第 \(i\) 条边 \(S\) 集合都存在的概率是否大于零。转移:
那么 \(u\) 最后存在概率大于零当且仅当 \(f_m(\{u\})=\mathrm{true}\)。状态数很多,但是终止状态固定,我们考虑倒推。
令 \(f_m(\{u\})=\mathrm{true}\),最后可以得到唯一的集合 \(G_u\) 表示得到 \(u\) 所必须删去的集合。
那么两个点 \(u,v\) 都存在的概率大于零当且仅当 \(G_u\cap G_v=\varnothing\),因为一个点不能够被删去超过 \(1\) 次。
用 \(\texttt{std::bitset<>}\) 实现,复杂度 \(\mathcal O(nm+n^3/\omega)\)。
T6
一个点可以到达的点集奇偶性相同,先分类。然后 bfs,用 \(\texttt{std::set<>}\) 维护未访问点集,访问一次后删去,可以保证复杂度。
9.3
暴力都能写假。
T1
又是分块。
T2
巧妙的 DP。按 \(y\) 从小到大 DP 是在没法优化。考虑按 \(x\) 坐标排序,统计每个点作为路径结尾最左 / 右端的贡献,每次枚举路径最左端,然后从 \(y\) 坐标较小的点向较大的点转移。
这样其实 DP 是没有后效性的,只是隐式的建了分层图。
T3
每个前缀后继状态唯一,manacher 预处理然后倒序转移一下可行性。
T4
首先有一段被操作的建筑会被增加至相同高度的结论,考虑枚举相邻的不变点进行转移,代价函数为 \(w(t)=\sum_{l<i<r}(t-h_i)^2+(h_l+h_r-2t)\times c\) 拆开后是关于 \(t\) 的二次函数,求对称轴算极值可以 \(\mathcal O(1)\)。
大部分转移是无用的,只需要在高度最接近的点对转移,用单调栈即可 \(\mathcal O(n)\)。
9.4
今天表演了一波写三题挂三题,状态差到极点。
T1
每个人的最优策略都是尽量占领两者之间的那条链。
\(\texttt{size[v] += size[u];}\)
T2
处理两点之间夹着的点集,然后是裸的状压。
题意最后求什么要仔细看哦。
T3
球的状态分为自己滚和被人带,自己滚因为两个方向无法之间转换,考虑建三层分层图。
最优方案下一个人最多经手一次球,否则可以调整为更优。因此可以 bfs 处理每个点最近的人的距离,也就是球从自己滚的状态转为被人带的状态的代价。
最短路就好了。
T4
分类讨论,然后套上倍增。
\(E\) 是定值,以 \(E\) 为根会好做很多。
9.6
T1
可以发现最小的两个数一定是 \(a_1+a_2,a_1+a_3\),考虑枚举 \(a_2+a_3\) 是哪个数,就可以算出 \(a_1\),然后就可以顺推其它数了。\(a_2+a_3\) 只用枚举到前 \(n\) 个,就可以 \(\mathcal O(n^3)\)。
T2
答案和逆序对奇偶性有关,只有奇数逆序对数的排列不合法。答案就是 (积和式 - 行列式) / 2,矩阵很特殊所以可以 \(\mathcal O(n^2)\) DP。
T3
筛出 \(\sqrt R\) 的素数,然后 \([L,R]\) 内枚举素数倍数进行埃氏筛。
9.8
水题大赛,不说了。
9.10
T1
每次询问满足 \(l < L \le r\lor l\le R < r\) 的区间 \([l,r]\) 的数量。
可以发现是树上两条链的并,倍增找起点。
卡常,要用树剖 LCA。
T2
\(1e18\) 内至多 \(15\) 个质因子,直接子集 DP。
单价函数 \(f(V)\),\(p\) 很小,考虑做同余最短路。
T3
折半。
T4
枚举每个药丸作为最后一个,那么剩下的一定是按 \(a_i-b_i\) 从大到小取。
难点在于判断是否合法,先排序,对于 \(i\) 作为结尾, \(1\dots i-1\) 合法性可以直接预处理,而 \(i+1\dots n\) 的点是于前面一位的 \(c_i\) 做差然后前缀和,也就是不断的往开头插入数、动态维护所有点的前缀和。
用权值线段树维护单点插入、整体加、查询权值范围内编号最小值,即可找到 \(i\) 之后第一次被淹的位置。
另外一个烂大街的贪心做法:二分答案天数 \(\mathrm{mid}\),然后每次 \(1\dots \mathrm{mid}\) 找 \(b_i\) 最大的作结尾,和 \(\mathrm{mid}\dots n\) 中 \(a_i\) 最大的作结尾,两种方案取最值。对于合法性,可以发现每次 \(1\dots \mathrm{mid}\) 无法移动至结尾的点是一个前缀,递推找到合法的范围。
upd:这东西完全不需要二分。
9.12
T1
DP 类似中国象棋。观察性质是每放玩一个或一对点,其中每个点对应的行列都不能再放。那么状态记录当前空的列,然后按行转移。
T2
Dilworth 引理,离线下来然后是二维偏序。
T3
考虑对于任意一个集合,去掉权值最大的元素后,可以唯一的变成一个优于它的集合。这是一个树形的结构,考虑类似超级钢琴的套路,用堆来找出第 \(k\) 大权值。
不过复杂度仍然不对,因为树上每个点的儿子数是 \(\mathcal O(n)\) 的,但是可以发现这些儿子之间的单调性,考虑转成二叉树。也就是将 \(a\) 序列排序后,每次对于一个集合 \(S\) 及其结尾元素编号 \(i\),其拓展出的儿子为 \(S\cup\{a_{i+1}\}\) 和 \((S\setminus \{a_i\})\cup\{a_{i+1}\}\)。
构造方案:既然权值小于等于 \(\mathrm{ans}\) 的方案不超过 \(k\) 个,那么直接搜索。从小到大每次加入一个元素使得权值和不超过 \(\mathrm{ans}\),用线段树或者主席树来找到编号范围内小于等于某个权值的最小编号,因为遍历到的每个方案权值和都 \(\le \mathrm{ans}\),所以复杂度 \(\mathcal O(k\log n)\)。
T4
\(\sum |t_{i+1}-t_i|\) 这样的式子,画在数轴上就是点移动的距离和,加上时间一维变成二维坐标系,发现是裸的线头 DP。
线头 DP 注意两端边界是否到达要记录进状态里。权值和 \(>L\) 的状态舍弃,复杂度 \(\mathcal O(n^2L)\)。
9.13
T1
如果条件是 \(L\le\mathrm{mid}\le R\) 的话,对应的答案就是区间内 \(1\) 的个数为奇数的区间数。然后再减去只有一个 \(1\) 并且位置在 \(L\) 或 \(R\) 上的区间数。
T2
树上每个点对应的两个儿子是一定的,那么确定了根也就确定了所有叶子各种类的数量。那么可以判断给出的三个数是否合法。
然后是构造字典序最小的解。可以发现每个高度只有 \(3\) 棵本质不同的树,可以直接递推,暴力比较字典序,让字典序较小的在前,复杂度 \(\mathcal O(2^n)\)。
T3
如果 \(n=m\),可以有 naive 的 \(\mathcal O(n^2)\) DP。
因为观察 DP 过程,如果令较大数相乘一定更优,所以将序列排序,最后选的一定是一个前缀和一个后缀,做上面的 DP 再枚举长度进行拼接。
T4
暴力能过。/jy
9.15
打了两个小时瞌睡。
T1
相邻的同色点配对后删掉,对其他点是没有影响的。不断重复这个过程,最后剩下 \(\texttt{010101}\dots\),此时只能够异色配对。
用栈来实现。
T2
\(m\) 非常小,把每个数的所有约数都暴力找出来即可。
T3
体积很大但是价值很小,把价值当作体积做背包。
修改很少查询很多,那么每次做完背包后,二分找到最大的价值满足其最小体积不超过 \(M\),做一个后缀 \(\min\) 即满足单调性。
T4
二分,合法条件为存在区间满足 \(\gcd=\min\),\(\mathcal O(n\log n)\)。
处理每个点作为 \(\gcd\) 所能扩展的最大区间。若 \(a_i\mid a_{i+1}\),那么 \(a_{i+1}\) 边界包含于 \(a_i\) 的最大边界,\(a_{i+1}\) 一定更劣。据此可以做到 \(\mathcal O(n)\)。
T5
考虑每个数 \(a_i\) 在每个位置,对 \(j\) 为开头时的贡献。
可以发现是两段等差数列,然后向左 \(i-1\) 位的循环偏移,可以二阶差分。
T6
行列之间的连通性是不影响的。我们直接去做 Kruskal 最小生成树,每条横向的边代表的是 \(n\) 条边,连接两列,因为有若干行在这两列上已经连通,我们只用连剩余行连通块数条边;竖向的边类似。
那么只需要把 \(n\) 行、\(m\) 列都看作点,对 \(P+Q\) 条边做 Kruskal,计算贡献时记得加权。
9.17
T1
两个方向 DP 然后拼一下。
T2
转化为求异色边。对于父亲暴力修改,儿子用 \(\texttt{std::map<>}\) 维护。
T3
按 \(k\) 分块,每次就只需要 \(\mathcal O(W)\) 合并两个背包。
需要注意开空间,用内存池和指针为好。
T4
每个点记录前 \(k\) 小路径,转移时只需要对两个有序序列归并,\(\mathcal O(nk)\)。
9.18
T1
每次移动一格起点,变化的位置只有 \(3K\) 个,只考虑这些位置产生的增量。
T2
贪心。最后的局面一定是一个环,首先每个点至多一个入度,所以保留最大的入边。
此时会形成若干环和若干链,我们要破环成链,若干链一定是能拼成环的。此时环上不能直接断掉边权最小的边,因为断开环后端口点可以和它的其它入边连接成新的链且更优。那么就要处理环上每个点入边的最大值和次大值之差,以此为权值断掉最小的边。
注意判断一开始就强连通的情况(小心 \(\rho\) 形环)。
T3
每个点肯定是要分两个方向拆点的。
可以再图上直接拓扑 DP,成环的位置遍历不到就是 \(-1\),其它部分便是 DAG,用 \(\texttt{std::bitset}\) 处理能到达每个点的点集,复杂度 \(\mathcal O(\frac{n^4}{\omega})\),满数据 \(3.2\mathrm s\)。空间开不下,但是任意时刻在队列里的点是 \(\mathcal O(n)\) 级别的,垃圾回收即可。
更优秀的。基于网格图的特殊性我们知道到达一个点必须要到达某两个前驱点,那么一行一行按顺序进行记忆化搜索,继承左边的点的答案,dfs 新增的点集,\(\mathcal O(n^3)\)。
T4
首先先染再折是最优的,并且只用需要染两种颜色。
每次折叠操作可以做到的是:
- 选一个一个分界点,较短一端删去,分界点所在连通块折半,放在边界;
- 边界连通块长度减一;
可以发现边界连通块是任意改变长度的,而中间的连通块只有长度为偶数时才有机会折半放到边界。容易除了边界以外的连通块长度为偶数是可行的充要条件。
一个偶数连通块一定可以拆成若干 2 连通块,如果我们需要最后包含颜色 \(c\),每个包含 \(c\) 的 2 连通块需要全染成 \(c\),其他连通块,其他 2 连通块只要染成剩余部分出现次数最多的颜色。
那么对于每种颜色,我们枚举中间连通块的起始位置,每次对一个颜色的数量增减 1,可以用桶动态维护出现次数最多的颜色。
9.19
T1
不考虑背包的限制,就是二维偏序。我们只要保证二维偏序的每一个状态都是合法的,也就能够让最后每个物品都能对应至少一个背包。
每个背包作用的范围是一个前缀,按体积从小到大做是困难的,因为当前物品是否占用背包会影响后续物品。那么可以从后往前做二维偏序,可以容易地判断当前状态的物品数是否超出限制,和限制取 \(\min\) 即可(较少的物品数是一定能达到的)。
T2
设 \(f(d,i)\) 表示高度至多为 \(d\) 的 \(i\) 个点的合法树方案数,答案可以对 \(f(d,n)\) 差分得到。
转移考虑对于根合并若干子树:根一定是编号最小的;剩下的子树互相独立,属于有标号集合的合并;为了避免子树合并顺序造成重复,每次令新加入的子树的根为当前编号最小的点即可。
复杂度 \(\mathcal O(n^3)\)。可以 NTT 优化二项卷积到 \(\mathcal O(n^2\log n)\)。
T3
题面太过分了。
一个子串是合法的当且仅当用栈做一遍后栈高为 \(0\),因为“凹”的可以交换一对字母的出入栈变成“凸”,栈高某一时刻 \(< 0\) 是没关系的。
然后哈希一下当前栈的状态统计一下。
T4
通分一下就是要找一对点 \((x_1,y_1),(x_2,y_2)\) 使得 \(\displaystyle\left|\frac{(Px_1-Qy_1)-(Px_2-Qy_2)}{Qx_1-Qx_2}\right|\) 最接近 \(0\)。
变换坐标为 \((Qx,Px-Qy)\),那么就是找到斜率最接近 \(0\) 的直线,一定产生于纵坐标最接近的点对,按纵坐标排序就可以了。
9.22
时间不太够。
T1
讨论一下 AAA, AAB, ABC 三种情况。每次枚举两个数,求逆后用 \(\texttt{std::map<>}\) 找第三个数。
T2
查询子树中值域范围内的点权和,放到 dfs 序上,主席树。
T3
二叉搜索树一个子树是一个区间,那么做区间 DP。对于区间枚举子树的根,发现子树的根的父亲只有两个选择,每个区间只需要记两个状态用于转移。
T4
赛时不会贪心,写个线段树优化建图然后跑 Dinic 最大流混了 70 分,后来拉个 HLPP 的板子直接过了。/jy
贪心。按照距一端的距离从小到大排序,让每个座位贪心地去匹配能到达它并且 \(s\) 最小的人。
另一端也是一样。
T5
模拟,没补呢。
T6
首先一个区间被另一个区间包含的话,这个小区间就是无用的。
此时一个区间作用的一定是序列上连续的一段,否则不优,所以只需要划分序列,令权值最大。处理每个点可划分为同一段的点的范围,\(\mathcal O(n^2)\) DP 即可。
9.24
T1
二分然后最短路,单调性感性理解。
T2
我们要求 \(\sum_{1\le 2i-1\le n}(2i-1)\times 9\times 10^{i-1}\)。
拆开式子 \((2i-1)\times 10^{i-1}\) 发现是可以用 \(10^{i-1}\) 和 \((i-1)10^{i-1}\) 表示的,矩阵快速幂。
更为优秀的做法是仔细推式子:
类似等比数列求和,裂项相消,
\(9\) 和 \(233333\) 互质,可以 exgcd 求逆元。
T3
裸搜都跑不了 \(0.01\mathrm s\)。
T4
裸的动态 DP。
9.25
T1
线性做法惨遭卡常,梦想选手白拿 45。
对于每个连通块,如果确定一个点的值,可以通过 dfs 树推出其他点的值。
那么将这个点设为未知量,将其他点都表示成关于这个点的一次函数,dfs 过程中用反祖边判断是否矛盾,用每个点的取值范围更新未知量的取值范围。
最后所有点的总和也是关于未知量的一次函数,可以根据范围直接求最值。
T2
转化题意为求出每个点左下方单调栈的大小。
按横座标从小到大做,用线段树在纵坐标上维护区间的单调栈。类似楼房重建,不显式地维护,只记录单调栈左右两端。合并两个单调栈,就在左边的子树二分出左单调栈第一个弹出的位置。
或者 CDQ 分治,y 坐标上考虑左区间对右区间的贡献的时候,以 x 为权值左右分别维护单调栈,然后每次在左单调栈二分第一个弹出的位置。
都是 \(\mathcal O(n\log^2n)\)。
T3
去掉 CEO 的领带后,贪心的策略是排序后排名相同的配对最优,因为此时最大值移动位置不会变得更优。
T4
每道菜需要至少 \(k\) 个人,那么可以让这 \(k\) 包括贡献 \(1\) 单位时间(记为基础时间),然后剩余的随意分配。
那么也就是我们要选出若干个人,时间总和 \(\ge \sum{a_i}\) 并且基础时间总和 \(\ge nk\),同时最小化时间总和。
最小化时间总和的话,我们尽量让每个人做的菜尽量多,贡献的基础时间一定是 \(\min(n,b_i)\)。
时间总和有下界又需要尽量小,这是需要具体记进 DP 状态的。
做背包,以时间 \(b_i\) 为体积,贡献的基础时间 \(\min(n,b_i)\) 为价值。最后答案就是基础时间总和 \(\ge nk\) 的最小的背包。\(\mathcal O(m\sum b_i)\)。
注意判一堆无解情况。
9.27
T1
建出虚树,然后对每条边代表的树链用重链剖分查询,主席树维护 dfs 序上区间的权值集合即可。复杂度 \(\mathcal O(\sum k\log^2n)\)。
后来发现求 \(\min\) 的话不需要建虚树,只要求出虚树深度最小的点,把每条叶子到该点的链的答案并起来就好了,直接在树上建主席树,除了 LCA 以外不需要树剖,会好写很多,就是 \(\mathcal O(\sum k\log n)\) 了。
T2
括号序列考虑放到网格图上向上或向右走的路径。
给出了一段路径,那么只要 \(\mathcal O((n-m)^2)\) 枚举这一段的起点,注意判一下结尾是否超出边界或者超过直线 \(y=x\),然后翻折法计算开头结尾两部分。
T3
\(+1\) 操作有进位难以处理,观察到性质:\(200 < 2^8\),\(n\) 次 \(+1\) 操作的进位至多影响低 \(8\) 位。
那么考虑状压低 \(8\) 位的状态,\(8\) 位以上只要记最低的连续段的颜色和长度。
可能会有低 \(8\) 位全是 \(1\) 然后 \(+1\) 进位,但是至多会发生 \(1\) 次,所以 \(8\) 位以上只用考虑 \(1\) 连续段变 \(0\),而不用考虑第一个 \(0\) 变 \(1\) 然后和前面的 \(1\) 连续段接上的问题。
复杂度 \(\mathcal O(n^22^8)\)。
T4
大模拟,不会,先咕。
9.29
今天太困了!睡到十点半才开始写,能混到 490 分也是服了。
T1
每次询问判断每个关键点是否在链上,然后各种模拟,细节题。
T2
略。
T3
首先 \(a_i\) 遍历的数是 \(\gcd(a_i,n)\) 的倍数。
那么一个数 \(k\) 能被遍历的充要条件是 \(\exists a_i,\gcd(a_i,n)|k\),也就是 \(\gcd(a_i,n)|\gcd(k,n)\)。那么让 \(k\) 在 \(\gcd(k,n)\) 处恰好被计算一次。
枚举 \(n\) 的约数 \(d\),如果 \(\exists a_i,\gcd(a_i,n)|d\),那么 \(d\) 会对所有 \(\gcd(k,n)=d\) 的 \(k\) 产生贡献。其数量为 \(\varphi(\frac nd)\)。
指数级的暴力容斥剪剪枝也是可以过的。
T4
去重麻烦,转化为最小化未打中的鸟数量。
从前往后不断加入线段,线段树维护区间加、区间最小值,用于 DP 转移。
T5
如果若干个环覆盖了 \(26\) 个字母会无解,这题很不严谨。
T6
Dilworth 引理。
九月份结束了。