这应该是这道题最易懂的题解了
题意粗解:
我们想要对一段连续递增的序列1,2,3...n进行[l, r]区间k次翻转,其中翻转区间可以不同。
暴力枚举:
我们很容易想到进行暴力枚举,即将每次将序列[l,r]区间进行枚举,将其进行翻转。利用reverse即可做到这一点。
但显然,时间复杂度为o(n*k),在 n,k <= 1e5 的情况下,即便是吸氧也无法保证不超时,所以我们必须换一个思路。
题目再观察:
观察题目可以发现:保证每次翻转的区间的起始点与终点都是非递减的,也就是说每次的l与r必定大于等于前一个l与r。
不难看出,这种情况是无后效性的。什么意思呢?
即:对于所有的i < l(这次操作的左端点),序列ai 在之后的操作中均不会再次发生变化,即进行翻转。他就被抛弃了
而对于r(右端点)来说,r只能加,也就是只能向右探索更多元素,而无法从右边舍弃已探索的元素。
所以,这实际上是滑动窗口问题。
开始构造:
鉴于滑动窗口问题的模版,我们考虑双端队列。
也就是说,我们不需要考虑一个元素被翻转了多少次,翻转到了哪里,只需考虑在某个特定区间内,该区间处于正序还是逆序。
比如在这个样例:1 2 3 4 5
假如我们想要对[2,4]区间进行翻转,我们就可以将{2,3,4}这个想要翻转的连续子区间储存下来,将其“逆序”。
然后逆序输出,即:1 {4 3 2} 5
接下来,假如出现了同样的操作[2,4],那么我们再将其从逆序转为正序输出即可。
那如果未来出现了[3,4]呢?
同样的可以观察:l从2变为了3,而方才我们注意到无后效性。也就是说,序列a[2]在进行翻转后永远不会再发生变化了。我们可以理解为:它不再活跃了。此时我们可以将它甩出去并输出。
比如: 1 {4 3 2} 5
滑动后:1 4 {3 2} 5
逆序: 1 4 {2 3} 5
可以看见,窗口滑动后,逆序的窗口滑出了第一个元素,即滑出了原来正序窗口中的最后一个元素。
但是,我们一味地将窗口进行逆序,k次操作下来仍然是o(n*k)的时间复杂度。那有没有办法进行优化呢?
我们可以考虑用nx储存该窗口是否逆序。每翻转一次,就将nx 变为 !nx。nx为1时代表该窗口逆序,否则该窗口为正序。
当该窗口逆序时,我们从滑出最后的元素,否则滑出最前面的元素。这与双端队列的操作恰好吻合。
同样的,加入新来的元素,当该窗口正序时,我们从后面加入元素,否则从前面加入元素。
样例分析:
1 3
2 4
2 5
实际数组 翻转后数组
第一步:{1 2 3} 4 5,nx = 0 {3 2 1} 4 5
第二步:3 {1 2} 4 5,nx = 1 3 {2 1} 4 5 滑出旧元素
3 {4 1 2} 5,nx = 1 3 {2 1 4} 5 加入新元素
3 {4 1 2} 5,nx = 0 3 {4 1 2} 5 翻转
第三步:3 {4 1 2 5},nx = 0 3 {4 1 2 5}
3 {4 1 2 5},nx = 1 3 {5 2 1 4}
最终数组:3 5 2 1 4
所以,构造完成~~~
你看这个赞,他又大又圆qwq
新人,码风不好望大佬们见谅0rz
#include<iostream>
#include<deque>
using namespace std;
int main(){
deque<int> huo;//储存活跃的元素
int n, k, l = 1, r = 1;
bool nx = 0;//逆序标记
cin >> n >> k;
while(k--){
int left, right;
cin >> left >> right;
//滑出并输出旧元素
while(l < left){
if(huo.empty()) cout << l << ' ';//若窗口没元素,说明该元素位置不变
else{
if(nx){cout << huo.back() << ' ';huo.pop_back();}
else {cout << huo.front() << ' ';huo.pop_front();}
}
l++;
if(r < l) r++;//如果l>r,同时更新l与r
}
//添加新元素
while(r <= right){
if(nx) huo.push_front(r);
else huo.push_back(r);
r++;
}
nx = !nx;//逆序正序互换
}
//如果活跃的元素没有输出完
while(!huo.empty()){
if(nx){cout << huo.back() << ' ';huo.pop_back();}
else {cout << huo.front() << ' ';huo.pop_front();}
}
//特殊情况:右边还有一些元素并未进行翻转
while(r <= n){
cout << r << ' ';
r++;
}
return 0;//好习惯
}

京公网安备 11010502036488号