Codeforces Round 1024 (Div. 1) 题解
Codeforces Round 1024 (Div. 1)
A
他妈被这种弱智题控了好久。总得来说刚开题根据样例改版猜出了构造方案,结果演算错了以为是错的,但是兜兜转转还是你,具体来说就是从一个角开始,当前值是 \(\max\),然后往一个方向走到角再转向,依次从小到大填数就行了,感性上理解是对的。
B
首先注意到一个数所在位置奇偶性不变,结合样例我们猜测奇数位偶数位的数分别排序是对的,但是发现它不对,比如 \(\{1,4,2,3\}\) 就败了。但是我们发现问题只会出在 \(a_n\) 和 \(a_{n-2}\),我们考虑判断他俩的顺序,结合这个反例与我们的操作我们不难猜到这个东西跟逆序对奇偶性有关,由于我们每次会在奇数位交换两个相邻的数,偶数位同理,那么逆序对奇偶性则会改变,若他们奇偶性本身就相等则最后一定可以交换到最优结果,否则 \(a_n\) 和 \(a_{n-2}\) 就不一定最优了。树状数组简单维护即可。
C
被这道题硬控了 1h,有点菜了。首先我们只关心每种颜色的 \(l_x,r_x\),对于不是 \(l_x,r_x\) 的位置我们并不关心。然后进一步我们发现如果两种颜色的区间不交则一定不优,这个时候我就开始乱想做法了。我们先考虑想出一个多项式做法,我们根据刚刚的性质似乎可以考虑求出每个位置表示每个区间都包含了它的最优答案,发现答案形式是 \(\sum r-\sum l\),并且对于确定的颜色数量 \(k\) 我们注意到选取的颜色一定是 \([1,k]\),于是我们发现 \(l,r\) 独立并且我们可以不用枚举每个位置了,我们直接求出 \(f(i),g(i)\) 分别表示最小化 \(\sum l\) 和最大化 \(\sum r\),但是这样是 \(\mathcal{O}(n^2)\) 的。但是我们从感觉上这个 dp 是可以反悔贪心的,实际上确实可以,只要我们固定了 \(k\),我们先按 \(a_i\) 排序,因为最终状态的分配显然也是这个顺序,具体就是如果 \(a_i\) 大于当前集合大小 \(|S|\) 并且 \(|S|<k\) 就加入,否则如果 \(i\) 比集合内的某个元素更优可以直接替换。
但是 \(k\) 并不固定,我们并不慌,我们发现这个东西是凸的,于是二分斜率就行了。
有时间还是得看看别人更优秀的做法。
D
是个难题,我不会,不知道为啥洛谷上评蓝,可能是为了搞笑吧。现在变成紫了。其实首先我们是不难发现合法的序列中,除了 LIS 之外都得在 LDS,并且还有一个交点。但我并没有注意到这个交点具有的强大性质,而是把充要翻译成了这个序列由一个上升子序列和下降子序列组成,然后就不会做了。
然而我们刚刚的充要并没有利用到合法序列具有的强大性质,突破口则正是产生的那个交点,我们能够发现确定交点等价于确定了 LIS 和 LDS,在其左边且小于它的一定在 LIS,在其左边且大于它的一定在 LDS,右边同理,只能说 attention is all you need。我们把每个位置找出合法的 \(l\) 和 \(r\),即满足条件的最小左端点和最大右端点,就可以简单计算答案了,做这些东西是可以简单做到 \(\mathcal{O}(n\log n)\) 的,但如果要求线性呢?
以找左端点为例,相当于是找第一次冲突的位置,我们来分析冲突产生的条件。首先画出来一种情况,不妨设 \(i<j<k\),那么当 \(a_k<a_i<a_j\) 时,我们发现无论如何都没救了!同理,当 \(a_j<a_i<a_k\) 时也没救了,我们不难想到一个序列不存在这样的三元组就是好的序列,那么我们对于一个位置要找到最大的 \(i\),我们考虑枚举 \(i\),求出 \(f(i)\) 即当 \(i\) 作为三元组中的 \(k\) 时最大的 \(i\),然后直接边做边取 \(\max\) 即可。这样子是可以简单线段树的,但是我们可以尝试找到更强的支配对,首先支配对满足的条件是 \(\min(a_j,a_k)<a_i<\max(a_j,a_k)\),现在我们猜测我们可以不妨令 \(j=i+1\),我们发现如果对于 \(i\) 已经存在一个三元组了,通过调整完全可以证明 \(j=i+1\) 足够了,那么我们扫描线时如果 \(a_i<a_{i+1}\),就相当于加入 \((a_i,i)\) 这个信息,对于枚举的 \(k\) 只要知道 \(a_k<a_i\) 的那些 \(i\) 就行了,\(a_i>a_{i+1}\) 同理,我们发现这个玩意可以单调栈,每次弹掉堆顶记录 \(\max\) 然后再插入当前位置要插的东西就行了。
E
完全比 D 简单吧。
首先这题看着倒是挺吓人的,感觉上不能重复走的限制令我们难以设计高效的 dp 状态,但是如果对每次乘以二比较敏感可以很快注意到我们是不可能走回去的,并且这题很显然的观察是顶多走 \(\log\) 步,那么我们再利用一点转置状态的技巧设 \(f(u,k)\) 表示 \(u\) 这个点要走 \(k\) 步前一步最多能够是多少边权,转移发现完全可以点分治于是做完了。
F
是个好题。
第一步是得注意到直径有较强的性质,我们这里可以找出蓝点集合内的直径,那么红点的有效贡献只会出现于直径的两个端点,进一步的,我们有一个结论,就是一个点到直径两点的最长路等于到直径中点的距离加上距离的一半,这是好证的,就是中点可能是点也可能是边,我们讨论一下就行了。
现在我们考虑枚举中点作为树根计数,首先要有两棵来自不同子树且深度相同的蓝点作为直径两端,并且两端也是最深的,其次要算红点的贡献,能产生贡献的也只有最深的红点,首先理清楚我们需要什么可以避免走很多弯路,这启发我们深度从大到小 dp,我们对点按深度从大到小排序,设 \(f(i,0/1,0/1,0/1)\) 表示考虑到第 \(i\) 个结点,前面子树是否在该层存在蓝点,该子树是否在该层存在蓝点,是否已经存在红点,直接转移即可。当然如果更深的已经有蓝点了那么中间两项都是一,算贡献时判一下即可。

浙公网安备 33010602011771号