牛客技能树:区间翻转

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

题目大意:给定一个排列:1,2,3...n,要求我们对该排列进行k次操作,每次操作给出l,r(区间 [l, r] 的 l 和 r 都是**非递减)**并对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;
}
相关推荐
青少儿编程课堂10 小时前
2026蓝桥杯·全国青少年信息素养大赛·电子学会Python/C++考级:堆排序与优先队列解析
c++·python·算法·bfs·信息学竞赛
SZYSK11 小时前
OpenHarmony 上读卡、推理和双屏刷新抢 CPU:核验机与消费机的调度差
物联网·算法·harmonyos·1024程序员节
Ivanqhz11 小时前
MoE + LLM 应用
数据库·人工智能·pytorch·python·深度学习·算法·1024程序员节
lpfasd12311 小时前
推荐算法进化史
算法·机器学习·推荐算法
Pniubi12 小时前
力扣543二叉树的直径(深度优先搜索法(递归))
算法·leetcode·职场和发展
UIU1141 天前
P1233 [ICPC 2001 Taejon R] 木棍加工
数据结构·c++·算法·动态规划
论文复现现场1 天前
WRF、FEA 能用 L40S 加速吗?求解器检查、断点恢复与长期运行
java·数据库·算法·wrf·有限元分析·gpu计算·断点续算
ZhengEnCi1 天前
用 AI 写代码为什么拼到最后还是拼人:算力瓶颈与领域专家提示词的本质差异
算法·架构
秋天的怀念_David1 天前
第二十一夜 · 数字黑洞与西西弗斯的惩罚
java·程序人生·算法
碧海银沙音频科技研究院1 天前
在PC电脑上用Whisper→Marian算法实现离线语音翻译功能
算法·whisper