Set To Max (Hard Version)

比赛遇到这种题目不要惊慌,一般都是用贪心

由于是序列操作题目,我们没有太多的办法,不可能把所有的情况都列举出来,所以根据贪心一般都有一个操作的顺序

这里我们按照\(b_i\)单调递增地操作,循环到某个\(b_i\)时,我们考虑\(a_i\)对应的数是多少,如果\(a_i<b_i\),我们考虑如何将\(a_i\)变成\(b_i\)

上面是我们的猜想,现在我们来证明这是正确的

对任意一种符合题意的操作序列,如果存在相邻的两次操作,使得前一次操作的\(x\)\(x\)的含义看题干)比后一次操作的\(x\)大,那么这两次操作一定是不相交的(否则后一次操作的\(x\)一定至少不低于前面一次的\(x\)),于是交换这两次操作,最终的答案显然也符合题意

也就是说,我们一定能找到一种合法的操作序列,使得每一次操作的\(x\)不降,所以我们可以从小到大考虑\(b_i\),而且我们后面的操作一定不会去影响前面的操作(这里后面的操作一定要是\(b_i\)增大了之后的操作,不能是不增的操作,实际上,我们的每次操作是考虑如何将所有相同的\(b_i\)对应的\(a_i\)改成\(b_i\)

我们再思考一下,就会发现,如果要将\(a_i\)改成\(b_i\),一定是找\(i\)前面或者后面最近的一个\(j\)\(a_j=b_i\),可以用决策包容性证明

可以想想以上操作怎么做,我的赛时代码是树状数组加st表,实际上可以用单调栈

我们以向右扩展为例,处理出每个位置\(i\)右边第一个\(a_j=b_i\)的位置\(j\)(设为\(pos_1\)),处理出\(i\)右边第一个\(b_j<b_i\)的位置\(j\)(设为\(pos_2\)),处理出\(i\)右边第一个\(a_j>b_i\)的位置\(j\)(设为\(pos_3\)),如果\(pos_2>pos_1\)\(pos_3>pos_1\)那么就可以变换

对于向左拓展是一样的,分享一个代码小技巧,我们对向右拓展写一个函数封装,然后将数组倒过来再写一个函数封装就好了

posted @ 2024-02-29 12:48  最爱丁珰  阅读(4)  评论(0编辑  收藏  举报