题解 P5069 【[Ynoi2015]纵使日薄西山】
更好的阅读体验
这篇题解的目的在于解释 @FlushHu 神仙题解中一些没有说清楚的细节部分。
Description
给定一个长度为
一次操作是指:找到序列的最大值的位置,如果有多个最大值则取最左边的,然后将这个数和这个位置左右紧挨着的数都
Limitation
序列值域在
Solution
第一次写 YnOI 体验极差
首先注意到的是如果确定要操作某个位置
先设序列中的数互不相同。考虑序列中一个单调递增或者单调递减的极长子序列,首先会操作最大值,减到
考虑修改的时候,只需要继续修改序列的极值点即可。
于是你就要面对这个点本来是极值点,本来不是极值点。他左边是极值点,右边是极值点,都不是极值点,改完以后极值位置不变,改完以后新增一个极大值,新增一个极小值等等十几种情况
考虑手动讨论每种情况显然非常不靠谱,但是注意到修改某个位置最多只会影响到这个位置向左右分别数两个极值点(不包括自身)这段区间的情况,同时新可能增加或者删除的极值点只有这个位置和这个位置左右各一个位置共三个位置。于是可以暴力重构这段区间的答案,由于求答案的时候只需要扫描区间内所有极值点,而极值点个数又是常数级别的,于是可以 set 的 lower_bound 造成的。
解释一下为什么会影响到左右数第二个极值点,如下数据:
9 2 6 8
三个极值点分别是
考虑如果序列中有相同的数怎么办:
如果相同的数不连续,那么根本不用管。如果连续,先假设这个这组数的第一个数大于左侧的数,那么操作到这组数的时候,这个数会被最先操作,于是这组数的第一个位置应该被设为极大值。如果这组数的第一个数小于左侧的数,那么第一个数是否被操作不由这个数决定,它不应该成为极小值。
考虑这组数的最后一个数,如果它大于右侧的数,那么这个数操作完以后会继续操作右侧的数,它不应该成为极大值。如果它小于左侧的数,那么左右两侧的区间都会在操作到这个位置的时候停止,那么这个位置应该成为极小值。
有一些细节:
考虑一个极小值会被操作,当且仅当它左右的数都没有被操作,那么它不会被减掉,只能自己单独操作。这种情况即它到左右的极大值点的距离都是偶数。
在扫描区间答案的时候,如果区间有
Code
写法上参考了 @FlushHu 神仙的代码,在此表示感谢,同时因此就不在这里放代码了,点击上面我的cnblog连接可以看到代码