March - May 做题合集
「省选联考 2024」迷宫守卫
首先考虑是最大化字典序,因此按位贪心。
考虑第一位怎么求。有一个简单的做法就是二分,然后转换成 \(0\)/\(1\) 然后 dp。就是令 \(f_{u,0/1}\) 表示让 u 这个点开始,走的第一个叶子最优是 \(0\)/\(1\) 的最小花费。然后再判断是否小于等于 \(k\)。
这个做法怎么扩展呢?
可以考虑把让第一位最优的最优决策(花费最小)保留下来,然后模拟 Bob 的行走,来判断 Bob 第二位的最优结果。
这个时候 Bob 是从一个节点回溯上来,要到另一个还没有涉足过的子树。
那么我们其实完全可以把将要前往的一棵子树内的决策清空,然后再算这个子树的最优决策。
发现这个做法有点问题。如果我们从 \(u\) 走到 \(u\) 的某个子树,那么 \(u\) 这个点的决策有可能改变。所以我们就枚举 \(u\) 这个点的决策,然后再暴力计算子树内的决策。
这样就做完了。时间复杂度 \(\mathcal O(2^nn^2)\)。然而其实二分 dp 可以换成更好的做法,把复杂度降到 \(\mathcal O(2^nn)\)。
「JOISC2019」時をかけるビ太郎
口胡。
首先相邻两个区间不交是极其简单的。随便讨论就可以了。
然后发现一段有交的区间等价于它们的交。于是直接把有交的区间缩成它们的交,然后转化成上面的情况,线段树随便做做就完事了。
「XR-3」系统设计
考虑直接哈希,把从根到某个点形成的序列哈希下来,并用线段树维护 \(a\) 序列哈希值,然后查询直接二分。复杂度 \(\mathcal O(n\log^2n)\)。
然而好像有 \(\mathcal O(n\log n)\) 的做法,我去研究一下。
「PA 2024」Alchemik Bajtazar
已经菜到这种题都要记了。
考虑一个菊花,这个图上任意两个点进行加边操作都是非常容易的。那么我们直接将原图变成菊花。具体操作就是将原图 bfs,然后由浅到深分别与根连边。这样可以 \(\mathcal O(n+m)\) 次将边集变成 \(E_1\bigcup E_2\bigcup \{(1,x)|x\in(1,n]\}\)。
注意到操作可逆,所以对终点图也进行这样的操作,最后再把这一部分倒着输出即可。总次数上界是 \(160000\)。
「ICPC World Finals 2021」地下城探测者
萌萌 ds 做不起了。首先考虑没有钥匙和陷阱的情况,那么就是总边权和乘以二再减去树的高度。然而有钥匙和陷阱。我们仍然可以分类讨论,具体想法就是枚举终点,然后根据其与钥匙位置,以及「钥匙与陷阱的 LCA」的位置关系分类,画画图就知道了。可以得到 \(\mathcal O(n^2+nq)\) 的做法。这已经能过原题了。
但是这样不好,我们考虑这样的问题可以直接树上倍增方便地查询,故而可以直接做到 \(\mathcal O(n^2\log n+q\log n)\)。树剖的话复杂度更优。
「PA 2024」Bardzo Ulubiony Ciąg
ZiBi 了。
我们考虑这样:枚举第一个区间的右端点和另外某一个区间,然后我们要匹配的就是这个区间的左端点和另外一个区间。然而我们第一个区间的右端点统计完答案过后,可以把它当作第一个区间的左端点直接与后面进行匹配。复杂度 \(\mathcal O(n^3)\)。然后再随便去去重就可以了。
「AGC024E」Sequence Growing Hard
考虑 \(A_i\) 到 \(A_{i+1}\) 的添加方式,怎么样才是合法的。显然一在一个数前面插一个数,这个数不能与它相等,因为这样会算重。而满足字典序的条件也很简单,就是插入在它前面的数比它大。所以一次插入相当于是选择一个数,并插入一个比它大的数,或是加入任何一个数。
我们考虑用树来表示这样的操作。令第 \(i\) 次插入的数加在第 \(j\) 次插入的数的前面,那么整个 \(A\) 序列就可以用一棵有根树表示,并且给每个节点一个权值表示插入的值,要求父亲的权值大于儿子的权值。对这个树计数,随便 dp 一下就可以了。时间复杂度 \(\mathcal O(n^3)\)。
「CF1037H」Security
通过这道题学习了线段树合并维护 SAM 节点的 \(\text{endpos}\) 集合。假定我们会了这个做法。
接下来我们只需要在 SAM 乱跳就行了,查询是查询某个节点的 \(\text{endpos}\) 集合中是否有 \([L,R]\) 中的元素,比较简单。时间复杂度 \(\mathcal O(|S|(|\Sigma|+\log|S|)+|T||\Sigma|\log|S|)\)。然而复杂度似乎可以再优化。
「HDU7171」Range Reachability Query
考虑暴力 bitset。这可以很容易过掉没有 \(l\) 和 \(r\) 限制的部分。然后你就直接对于每个点记录他能否满足每个询问的同行。转移的时候对于每个询问你都一与上这条边是否属于这个询问的范围。与的这个东西也可以 bitset,预处理一下就可以了。然后有可能 MLE,处理方式是分成几组跑就可以了。挺暴力的,但是中间那一步还是比较厉害。
「ABC236Ex」Distinct Multiples
对于连通图容斥,我们可以得到容斥系数为 \(f(S)=-1^{|S|-1}(|S|-1)!\),然后随便 dp 就做完了。至于为什么容斥系数是这个,咕咕咕。
「USACO24OPEN」Identity Theft P
可以发现我们按自底向上的贪心是对的。我们考虑将 \(u\) 移到下面某一个合法的位置,有两种情况,一种是直接移到一个新的子树,并且它到这条子树的路径上没有其他点,另一种是把一个叶子往下移腾出位置来,让他下去。这两种决策直接用可并堆维护,不是很难。时间复杂度 \(\mathcal O(|S|\log|S|)\)。
「JOISC 2017」港湾設備
感觉我的做法非常繁琐。首先我们考虑放到圆上,那么合法条件就是同一个港口的每个货物首尾连成的线段没有交点。然后相当于有交点的线段之间有一条边,然后二分图染色的方案数。假如连通块数量为 \(m\),并且每个连通块都是二分图,那么答案就是 \(2^m\)。然而怎么算 \(m\) 呢?我们可以把线段按照右端点从小到大排序,然后每次加入一条线段时将其和若干个已有连通块合并。这可以线段树维护。但是这并不能说明是否存在非二分图。于是可以把得到的这个保持原有连通性的子图拿来黑白染色,再判断就行了。染色过后的判断是简单的。时间复杂度 \(\mathcal O(n\log n)\)。
「ABC221G」Jumping sequence
有一个很厉害的 trick。考虑到两个方向有影响,我们将坐标轴转 \(\dfrac{\pi}{4}\),这样我们发现原先的四个操作可以对于 \(x\) 轴和 \(y\) 轴独立考虑了。然后做两遍 dp 就完了。直接用 bitset 可以过,但是有更炫酷的做法,等我实力变强后再学习。
「USACO24OPEN」Splitting Haybales P
通过此题学习了非常厉害的平衡树合并啊!有均摊,\(\mathcal O(n\log^2n)\) 暴力直接秒了。注意一下暴力的写法,非常厉害啊。
「CF1017G」The Tree
其实这个题的维护方法很有启发性。对于操作 1 和询问,我们可以直接在操作的点上加标记,查询的时候可以推出是查询一条链上的后缀最大值。然后清空操作其实也就差不多了,将子树清空,然后在该点减去自身的查询值,可以保证查询没有问题。时间复杂度 \(\mathcal O(n\log^2n)\)。但是其实清空操作的正确性需要证明吧?
哦,其实只需要知道的是操作过后该点的查询值也变成 \(-1\) 就行了。
「Ynoi2010」y-fast trie
考虑 \(i+j<C\) 的情况,\(i\) 肯定匹配小于 \(C-i\) 的最大的。同时对于最大的 \(i\) 和 \(j\),必然彼此互为最大的关系。故直接维护双向最大关系,然后发现这样插入弹出修改的数量就是 \(\mathcal O(1)\) 级别的了。
「UR #8」决战圆锥曲线
这么深刻的题!维护区间最值,然后考虑询问操作。我们先递归右子树,再递归左子树,并且遇到某个时刻 \(x=r\) 并且 \(y=Y_\text{max}\) 时的 \(ax+by+cxy\) 比小于等于当前找到的答案,直接退出递归。这样每一次递归的纵坐标最大值一定递增。又有数据随机,所以最多只会递归到 \(\mathcal O(\log^2n)\) 个节点。
「AGC001E」BBQ Hard
竟然没有做过这么深刻的题!!!考虑组合意义就是从 \((-a_i,-b_i)\) 走到 \((a_j,b_j)\) 的方案数。那么可以直接 dp,记 \(f_{x,y}\) 为所有起点走到 \((x,y)\) 的方案数之和,转移是平凡的,然后再处理一下就可以了。不愧是 JPOI 的题目啊!!!
「Codechef」CyclesAndColorings
题目持续深刻。随便找一个生成树,如果非树边构成二分图,则对树边和非树边分别二分图染色再合并,否则找到非树边构成的一个奇环,删掉,一定不影响连通性。还有一个加强版说的是四染色改成三染色,这个就考虑 bfs 找生成树,然后相邻的拓展颜色取反。这样非树边如果是二分图,则一定是有良好性质的,乱做做就可以了!构造题啊!
「Ynoi2011」成都七中
非常厉害的题目。考虑点分治,若某一次分治中心第一次在某个询问所在的连通块,那么这个连通块一定包含于这个分治中心所分治的连通块。证明显然。然后再把这些询问拎出来。另一方面对于一个点,我们只需要关心它到分治中心路径上点编号的最大值和最小值。然后就是一个二维偏序数颜色,时间复杂度 \(\mathcal O(n\log^2n)\),想清楚了很好写好调,算是小清新数据结构。
「QOJ1286」Ternary String Counting
题目质量很高,但是如果我退役了就没有用。/kk
考虑一个非常厉害的 dp:定义 \(f_{i,j,k}\) 表示填入了前 \(i\) 个数字,满足右端点为 \(1\) 到 \(i\) 的所有限制,并且上一个与 \(i\) 颜色不同的位置为 \(j\),与两个颜色都不同的位置为 \(k\) 的方案数。那么不考虑限制的话转移非常简单。假如考虑从限制,那么我们实际上会发现这个其实是对 \(j\) 个 \(k\) 的限制,相当于对于一些 \(j\) 和 \(k\) 使得 \(f_{i,j,k}=0\)。而经过推算发现保留下来的区域是个矩形。并且由于问题的特殊性,被清掉的位置不再会有值,所以直接暴力就可以做到 \(\mathcal O(n^2)\) 了。
「CF1630F」Making It Bipartite
复习了很多很多图论基本定理。膜拜 cqbzxzj!!!
考虑一个点不能同时成为因数和倍数。于是考虑建点 \(u_0\) 表示 \(u\) 为因数,\(u_1\) 表示倍数,如果都不是就随便选一个。那么我们就需要的是 \(u_0\) 和 \(u_1\) 连边,以及对于一些倍数关系进行连边。问题就是一般图最大独立集。注意到这个图可以进行边的定向使得其成为有向图。可以发现这样它就变成了偏序集。而偏序集最大独立及等于最长反链覆盖,等于最小链覆盖。至此就可以二分图匹配做了。
一般地,我们对于有向图求最小链覆盖,让 \(u_L\) 与 \(v_R\) 连边。形成的二分图跑最大匹配就是了。证明就考虑一个点最多只有一个入度,一个出度,而选的边数最多的覆盖即为最小链覆盖。
「Ynoi2014」不归之人与望眼欲穿的人们
这题怎么会只评紫呢?
首先考虑一个关键结论,固定一个端点,另一个端点随便移动,得到的区间 or 和的种数是 \(\mathcal O(\log V)\) 的。然后大力使用这个结论就好了。据此有一个分块做法。块内贡献可以在重构的时候 \(\mathcal O(B\log V)\) 算出,跨块贡献可以依旧维护 \(\mathcal O(\log V)\) 的分段函数,前缀所有块和右边一个块归并,并快速并上一个新块,复杂度是 \(\mathcal O(\dfrac{n^2\log V}{B})\)。综上,复杂度是 \(\mathcal O(n\sqrt n\log V)\)。还有一个 \(\mathcal O(n\log^3 V)\) 的做法,大概就是枚举修改点左右各 \(\mathcal O(\log V)\) 段,然后对每种值的出现次数进行维护。但是实际运行效率可能不是很好。
「P4198」楼房重建
感觉最近天天在做数据结构。
考虑线段树维护区间斜率最大值与区间答案(即区间严格前缀最大值数量)。那么怎么 pushup
呢?显然区间答案不能直接加,也不是很好算。这个时候我们考虑递归。令执行 pushup
的点为 \(p\),则 \(p\) 左儿子的答案可以直接累加。然后我们递归右儿子,同时记录一下 \(p\) 左儿子的区间最大值。令其为 \(L\)。递归到一个点 \(q\) 时,假如 \(q\) 左儿子的最大值小于等于 \(L\),那么 \(q\) 的左儿子中没有任何一个数会成为答案,直接递归右子树。否则在此种情况下 \(q\) 左儿子的最大值一定在答案序列中,则可以考虑 \(q\) 的答案减去其左儿子的答案,得到的一定是当前情况下 \(q\) 右儿子能够贡献的答案。然后再递归算 \(q\) 左儿子的答案。复杂度 \(\mathcal O(n\log^2n)\)。感觉很神妙。并且似乎还有 \(\mathcal O(n\log n)\) 的高论。
「BZOJ3569」DZY Loves Chinese II
题解认为是套路题目。看来是我太菜了。只讲做法:找一棵生成树,所有非树边在 \([0,2^{64})\) 中随一个权值。而树边的权值是覆盖他的非树边的权值的异或和。可以极其近似地认为删掉 \(k\) 条边后图连通的充要条件是这 \(k\) 条边的权值在异或意义下线性无关。
「LOJ3080」国际象棋
考虑 \(n\) 和 \(m\) 同阶。最暴力的高斯消元是 \(\mathcal O(n^6)\) 的,带状矩阵消元可以优化到 \(\mathcal O(n^4)\),然而还是不足以通过此题。
我们发现移动方式很死板,我们完全可以只将前两行和第一列的值设为未知数,通过 \((n-2)\times m\) 个方程用这些未知数表示所有的值,另外的方程拿来求解,刚好足够。时间复杂度 \(\mathcal O(n^3)\)。这个 trick 之前好像用过,但是忘完了。
「JSOI2008」魔兽地图
自己做出来了,但是感觉还是比较牛。定义状态 \(f_{i,j,k}\) 表示 \(i\) 这个点已经买过 \(j\) 次(仅仅以此表示子树内基础节点剩余购买次数),且剩余的钱为 \(k\),买 \(i\) 子树内的装备新增的最大力量值。转移就不难了。
「NOI2015」寿司晚宴
很牛的题目。我能够自己想出来,太牛。我们把 \(n\) 以内的质数按与 \(\sqrt n\) 的大小关系分成两部分。对于小的那部分我们记录一下能不能用,对于大的部分,比如当我们枚举到 \(p\) 时,一次性决策 \(p\) 的所有倍数。因为它的倍数里的质因子除了 \(p\) 都是可以用状态表示的。就做完了,运算量大概是 \(500\times 2^8\times 2^8\) 这个级别。
「THUPC2019」过河卒二
十分套路,但是还是有一些比较牛的点的。比如说我们可以直接把终点定到 \((n+1,m+1)\),这样就不用处理边界了。
「CF1975F」Set
待补。
「NOI2018」冒泡排序
待补。