BJOI2021游记+题解

游记点我

题解

Day1T1卡牌游戏

我唯一场上过的一题(结果被许多假做法过了),不过说不定我的也是假做法呢

首先我们发现要求极差的话,(a_i,b_i) 分开的话很不好处理,所以我们把所有 (a,b) 放到一起按照值排序。
我们可以发现,我们实际上就是要 ( ext{ban})(n) 个点,而如果我们发现我们的极差是 (t[r]-t[l])(其中 (t) 是把 (a,b) 重排并放到一起之后的数组)
那么我们可以发现,我们一定 ( ext{ban}) 掉的是 (t_1)(t_{l-1}),以及 (t_{r+1})(t_n)。那啥是合法的,啥是不合法的呢?
发现如果 ( ext{ban}) 掉的点中,有超过 (m)(b_i) 或者有同时 ( ext{ban})(a_i,b_i)(i) 相同)的情况,就不合法,双指针维护即可。

Day1T2矩阵游戏

考场 (50pts) 写挂,但是还好数据水,没有挂分(

首先我们可以发现,如果没有 (1le a_{i,j} le 10^6) 的限制,可以直接钦定 (a_{1,i}=a_{j,1}=0),然后直接算后面的值就好了。
然后我们又可以发现,给奇数列 (+r_i),偶数列 (-c_i),行则是加或减 (t),正确性仍然满足。
然后我们每一个数就可以写成 (a_{i,j} +_- r_i +_- c_j) 其中 (+_-) i表示加或减法,然后就可以直接差分约束了。吗?
不行,因为会有形如 (a_{i,j}+r_i+c_j),这样会很麻烦,所以我们考虑将 (r_i(i=2k+1)) 取反,将 (c_i(i=2k)) 取反,就 (OK) 了。
最后会形如这样

一个细节:由于我们如果将所有 (r'_i,c'_i) 都加上 (Delta),结果完全一样,所以我们直接钦定 (r'_1=0) 即可。

Day2T2图函数

考场看错题写了一个 (44pts) 然后被卡常了。。。

首先,我们可以将问题转化一下,给定一个 (u,v),找到一条 (u ightarrow v,v ightarrow u) 的路径且只经过比 (u,v) 编号大的点。
证明:如果 (u,v) 借助一个点 (w(w<u)) 联通了,那么 (w) 一定没有被删,但是因为 (u,w) 联通, (v,w) 联通,所以 (u,v,w) 在一个强联通分量中,所以 (w) 已经被删了。
而一个 (u ightarrow v) 能对 (h_i) 做贡献的话,那么它一定能对 (h_{i-1}) 做贡献。
所以我只要找到一条 (u ightarrow v) 的路径使得经过的边的编号最小值最大,这个只要倒序加边,然后每次 (bfs),注意答案确定的 (bfs) 就不用经过了,所以每个边只会经过一次。
最后差分计算答案即可。
时间复杂度 (O(nm)),要卡卡常才能过去。

Day2T1宝石

被原题埋伏了。。。如果考场上过了这题我就到队线了。。。

我们考虑在一条链上怎么做。
首先,如果我们在一个点收集的一颗宝石,那么我们要收集的下一颗宝石的位置是确定的,然后我们直接建图然后倍增即可。
注意第一个宝石不能这么做,不过可以直接从后往前扫一遍就可以知道离它最近的颜色排序为 (1) 的点了。
时间复杂的 (O(nlog n))
那在树上怎么做呢?
发现其实一样,我们可以维护一下里这个点最近的所有颜色,不过就不能扫一遍了,必须要维护一个主席树。
发现 (s-lca-t) 的这两段路程中 (s-lca) 的那段简单,直接用链上的方法即可,不过那么 (lca-t) 的路程,我们的终点是不确定的,所以没法直接找到。
所以考虑二分一下终点,然后直接按照之前的方法维护一下即可。
时间复杂度 (O(nlog^2 n))

Day2T2滚榜

这题发现部分分给的很多,于是打完 (60pts) 之后就没想正解了,其实正解也并不是很难。。。

首先,我们可以将恰好为 (m) 等价为不超过 (m),因为多了的话可以直接扔给最后念出的人,并且完全合法。
我们发现,因为 (b_i) 单调不降,所以我们给一个 (x) 点加了一个 (val) 之后,剩下的东西肯定都要加上一个 (val),所以我们提前给它加了。
这样的话比较上一次念出的人和这一次念出的人的大小关系就很容易确定了(也就是原先的大小关系,因为都加了同一个 (val)
我们用 (dp[i][p][st]) 表示上一次念出的是 (i),目前用了 (p) 滚榜的过题数的,目前念出的人的状压状态为 (st) 的方案数。
我们枚举 (j) 表示下一个要念出的人是 (j),直接转移即可。
时间复杂度 (O(2^nn^2m)),需要经过卡常才能过题

Day2T3支配

这题要用支配树,所以考场我直接暴力滚粗了,后来发现 (O(n^2)) 的支配树其实很好写

我们先用 (O(n^2)) 把支配树建出来,具体就是先 (n)(dfs) 把每个点的受支配集(也就是支配它的点)找出来。
然后用拓扑排序的方法,首先将 (1) 入队列,然后每次消除支配关系,如果一个点没有被支配了(或者说支配的它的点都入树了)
我们可以就直接让它上支配树,而父亲是它的受支配集中的最后入支配树的点,然后就建好支配树了。
我们发现,如果一个边 (x ightarrow y) 可以改变 (u) 的受支配集合,那么所有 (u) 的支配树上的子孙也都可以被改变。
那我们可以想一想 (x ightarrow y) 什么时候能改变一个点 (u) 的受支配集合?也就是存在一条边可以 (1 ightarrow x ightarrow y ightarrow u)
且这条路不经过 (u) 在支配树上的父亲。
对于 (1 ightarrow x ightarrow y ightarrow u),我们感觉很难受,所以分成 (1 ightarrow x) 以及 (y ightarrow u)
我们发现 (1,x) 都是确定的,所以很容易判断一个点在不在 (1 ightarrow x) 上,但是,(u) 是不确定的,所以我们考虑预处理出 (y ightarrow u) 不经过 (fa[u]) 的路径
具体是枚举 (u),然后 (ban)(fa[u]),跑 (dfs),如果能到一个点 (t),那么 (f[u][t]=1) 即可。
最后就是判断 (1 ightarrow x) 路径上有没有 (fa[u]) 了,由于可以允许 (O(nq)) 的做法,所以直接暴力找并标记就好了。
时间复杂度 (O(nq)),细节挺多的,最好注意一点

原文地址:https://www.cnblogs.com/chen-1/p/14674678.html