牛客技能树:区间翻转

题目链接:https://www.nowcoder.com/practice/34e434465a3b46d29c581fee5d73bc81?channelPut=tracker3

题目大意:给定一个排列:1,2,3...n,要求我们对该排列进行k次操作,每次操作给出l,r(区间 [l, r]lr 都是**非递减)**并对l,r进行区间翻转,输出最终排列

题目思路:暴力解法很容易想出,但是会超时,所以我们可以使用双端队列 + 翻转标记来做。

核心思路是:

  • 所有操作区间的左端点和右端点都单调不降,所以每次操作的区间可以看作一个向右滑动的窗口。

  • 用双端队列 q 保存当前窗口内的元素。

  • rev 标记当前队列是否被整体翻转,这样翻转窗口只需要 rev = !rev,不用真的移动元素。

  • 窗口左侧已经确定的部分存入答案数组 ans;右侧还未进入窗口的数字用指针 cur 表示。

代码如下:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
//#define int long long
#define endl "\n"
void solve()
{
    int n, k;
    cin >> n >> k;
    deque<int> q;//当前窗口中的元素
    bool rev = false;//true表示q中元素实际是反向存储的
    int L = 1, R = 0;//当前窗口在数组中的下标范围,初始为空
    int cur = 1;//下一个还未进入窗口的原始数字
    vector<int> ans;
    while(k--){
        int l, r;
        cin >> l >> r;
        //窗口左边界移动到L,左边固定部分弹出到ans
        while(L<l){
            if(L<=R){
                //窗口非空,根据rev方向弹出对应
                int x;
                if(!rev){
                    x = q.front();
                    q.pop_front();  
                }else{
                    x = q.back();
                    q.pop_back();
                }
                ans.push_back(x);
            }else{
                //窗口为空,该位置从未被操作过,原始数字L直接固定
                ans.push_back(L);
                if(cur<=L)
                    cur = L + 1;   
            }
            L++;
        }
        //右边界右移:将新数字纳入窗口
        while(R<r){
            R++;
            if(R>=L){
                //窗口有效,将下一个元素数字cur加入
                //注意:根据rev方向,物理上要加到相反的一端
                if(!rev){
                    q.push_back(cur);
                }else{
                    q.push_front(cur);
                }
                cur++;
            }
        }
        // 若R<L,说明窗口还未真正形成(左边界在右边),暂时不加入
        // 执行区间翻转:只改标记
        rev = !rev;
    }
    //已固定的左侧部分
    for(int x:ans){
        cout << x << " ";
    }
    if(!rev){
        while(!q.empty()){
            cout << q.front() << " ";
            q.pop_front();
        }
    }else{
        while (!q.empty())
        {
            cout << q.back() << " ";
            q.pop_back();
        }
    }
    for (int x = cur; x <= n;x++){
        cout << x << " ";
    }
    cout << endl;
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int T=1;
    //cin>>T;
    while (T--)
    {
        solve();
    }
    return 0;
}
相关推荐
数模竞赛Paid answer10 小时前
2026年五一杯数学建模C题边坡预警问题求解全过程文档及程序
算法·数学建模·五一杯
hold?fish:palm11 小时前
20 旋转图像
c++·算法·leetcode
NoteStream11 小时前
【C语言基础】分支和循环(上)
c语言·开发语言·c++·经验分享·笔记·算法·c#
白狐_79811 小时前
408数据结构第7章:查找②——顺序、折半、分块查找秒杀 + 真题
数据结构·算法
卷心菜的学习路12 小时前
基于多模态向量检索的数学相似题推荐系统:完整设计、算法与实验
java·python·算法·大模型·推荐算法·数学相似题
小南知更鸟12 小时前
【leetcodehot100】leetcode-hot100-20260809更新
算法·leetcode·职场和发展
数模竞赛Paid answer12 小时前
2021年深圳杯数学建模A题火星探测器着陆控制方案解题全过程论文及程序
算法·数学建模·深圳杯
hold?fish:palm12 小时前
19 螺旋矩阵
线性代数·算法·矩阵
码完就睡13 小时前
数据结构——树、二叉树基础概念
数据结构·算法
VL——MOESR13 小时前
【LuoguP1967】货车运输【生成树】【倍增】
c++·算法·题解·倍增·生成树