牛客技能树:区间翻转

题目链接: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;
}
相关推荐
tkevinjd9 小时前
力扣148-排序链表
算法·leetcode·链表
qeen879 小时前
【C++】vector的模拟实现详解(二)
c++·学习·算法·迭代器·stl
沉迷学习 日益消瘦11 小时前
4 净资产趋势可视化:SVG 图表 + 手势交互 + 降采样算法
算法·交互
可编程芯片开发21 小时前
基于MATLAB的PEF湍流风场生成器模拟与仿真
算法
罗西的思考1 天前
【Agentic RL / 强化学习 / OPD】OpenClaw-RL 源码阅读笔记 --- (9)--- Reward Judging
人工智能·算法·机器学习
Mr.HeBoYan1 天前
一次持续三天才出现的丢包故障——深入解析 DPDK Memory Ordering、rte_ring 与 CPU Memory Barrier (下)
linux·网络·算法·架构·dpdk
wabs6661 天前
关于图论【深度优先搜索的理论基础】
算法·深度优先·图论
先吃饱再说1 天前
LeetCode 101. 对称二叉树
算法
是Dream呀1 天前
人眼看不出的伪造,AI如何识别?实测合合信息跨模态鉴伪与去反光技术
算法