【题解】Solution Set - NOIP2024集训Day1 数据结构

【题解】Solution Set - NOIP2024集训Day1 数据结构

https://www.becoder.com.cn/contest/5429


「CF1428F」Fruit Sequences

线段树是可以维护区间最长子段的 1。

记固定右端点在 \(i\),的答案为 \(f_i\)。那么:

  1. \(a_i=0\)\(f_i=f_{i-1}\)
  2. \(a_i=1\),打一个单调栈维护所有的最长子段,然后来更新 \(f_i\)

p.s. 代码里面的定义有些不一样。


「2021牛客暑期多校训练营2 - G」League of Legends

有一道几乎一样的题 NOIP模拟赛1 T3 色题解

不一样的是这道题不允许有空集,也就是说一开始存在空集的情况就排除掉了。

然后在 dp 的时候,不能直接前缀和,还需要一个单调队列,来判一下合不合法。


p.s. 很好,下面是自己的思路,可以发现几乎全部错了 QAQ,所以就别看了。(唯一值得高兴的是看了之前的题解之后,一次性改对了

问题主要如下:

  1. 一开始的结论就假了,没有考虑完全包含的情况。以后还是需要再多想一下;
  2. \(calc(i,j)\) 因为必须有交集,实际上就等于 \(r_i-l_j\),而没有想到这个这个的话断送了后面优化的路。

下面是原文:

有难度。👍

先思考一些性质。

首先,对所有区间排序。

然后,可以发现划分出来的 \(k\) 个组每个组都一定是连续的(可以反证),这样就很好 dp 了。

定义 \(f_{i,j}\) 表示前 \(i\) 个中分为 \(j\) 组的最优解,\(calc(i,j)\) 是第 \(i\) 个区间到第 \(j\) 个区间交的长度。有转移:

\[f_{i,j}=\max_{k=1}^{i}\{\{f_{k-1,j}+calc(k,i)\},f_{i-1,j-1}+r_i-l_i+1\} \]

然后发现对于相同的 \(i\)\(calc(i,j)\) 随着 \(j\) 的增大而减小,而且越靠前的 \(i\) 减小的越快。

所以我们可以维护一个 “类单调队列”。

末端加入元素的时候,需要保证比前面的优。

然后队首删除那些

所以有决策单调性,预处理出 \(calc\),然后就可以 \(O(n^2)\) 做了。


「ARC067F」Yakiniku Restaurants

首先走回头路肯定是更劣的,所以最终答案一定是走的一个区间。

\(a\) 求前缀。

考虑一个区间 \([l,r]\) 的答案应该是:

\[Ans_{l,r}=\sum_{i=1}^m \max_{j=l}^rB_{i,j}-(a_{r}-a_{l}) \]


想一想用 ST 表可以做到 \(O(n^2m)\),但是还是过不了。

\(m\) 很难搞掉,所以考虑搞掉一个 \(n\)

自然想到 two-points。

正确性?

对于一个右端点 \(r\),设她的最优左端点为 \(l\),记作 \([l,r]\)。对于 \([l,r+1]\),设左端点变为 \(l-1\) 之后,\(B\) 求和的增量为 \(\Delta\),那么对于 \([l,r]\),该值一定是 \(\le \Delta\) 的,而要减去的 \(l-1,l\) 之间的距离是不变的。也就是说左端点左移的贡献在减少!故而左端点一定不会左移。


好吧,事实证明,正确性的问题有点大😥

two-points 是错的,因为左端点向右移动的时候,可能先是不优的,然后再是最优,所以就 G 了。

https://www.becoder.com.cn/submission/2566864


https://www.luogu.com.cn/article/9rwufdjc

事实上,还是得搞掉一个 \(m\)。我们不妨把 \(B\) 对每个区间的贡献提前加上。

先预处理当前 \(B_{i,j}\) 作为最大值的极长子段。设为 \([L,R]\)

然后对于左端点在 \([L,i]\),右端点在 \([i,R]\) 的区间,一定是 \(B_{i,j}\) 做贡献。用二维差分实现二维矩阵加法。

然后再 \(O(n^2)\) 枚举左右端点就行了。总时间复杂度 \(O(nm+n^2)\)


做完上面两道题,感觉小脑萎缩了😭

每次想的都是错的,而且感觉有点过度深挖性质了。

实际上直接面对这个式子,直接处理可能就行了。


「ARC072F」Dam

dp 的话,\(O(nt^2)\),难以优化。

考虑到,最后的形式一定是:

\[\dfrac{\sum v_it_i}{L} \]

所以就是要最大化分子。

题解(可以稍微看一下 \(f\) 的定义,然后我自己按照自己感觉更自然的思路来理解了一下。

我们考虑把整个过程抽象成函数上。以此来挖掘一些性质。

具体在这道题上,就是题解中所定义的 \(f\)

将每一天的操作分为如下两步:

  1. 加水: 先不考虑容量限制。整个函数就相当于在最开始加一条线段 \((0,0)-(v_i,v_it_i)\),然后再在另一个端点接上原来的函数。

    因为每次我们都是加入了一个单增的东西,而后面的东西增减性不变,所以整体就一定是单增的。

  2. 倒水: 对于任意容量为 \(x\) 的状态开始倒水,其实就是从这个点向原点连一条线段,表示上面的点都可以得到。

    又因为要取 \(\max\),并且函数单增,所以整个函数应该上凸的。


然后就要用单调队列维护这个上凸包。

首先第一步要求我们整体平移,所以我们直接维护每一个拐点和前一个的差值。

第二步要求我们找到斜率最大的一个拐点,然后用这条线段替换掉前面的所有线段。

线段维护单调栈板子

posted @ 2024-08-07 11:29  CloudWings  阅读(11)  评论(0编辑  收藏  举报