蓝桥杯 双向排序【第十二届】【省赛】【A组】

这篇博客主要探讨了蓝桥杯省赛中一道C++题目,涉及到双向排序的问题。作者指出,原题中直接使用sort函数会导致超时,因为存在大量无效操作。解决方案是通过优化算法,去除重复和无效的操作,如利用栈来存储操作记录,并通过比较栈中操作的范围来消除无效的排序。文章提供了多个优秀解法的代码示例,解释了如何高效地处理双向排序任务,从而避免时间复杂度升至O(n^2)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

资源限制

时间限制:1.0s 内存限制:256.0MB

简介

开始以为是超级水题,想着直接用sort就秒杀了,结果秒提交却TLE了...只得了60分......仔细想想,原来的数列是连续有序的,而sort是利用快速排序实现的,快速排序在原数列全有序的情况下可达到on^2.而且,显然存在大量的重复可抵消的无用操作,示例中的就有存在的重复操作之一。要想AC,就要除去这些无效操作。

贴上60分蒟蒻代码和佬们的代码以及来源

#include<bits/stdc++.h>
using namespace std;
int n, m,p,q;
int a[10010];
int main(){
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= n; i++)
		a[i] = i;
	while (m--) {
		scanf("%d %d", &p, &q);
		switch (p) {
		case 0: {
			sort(a+1 , a + q+1,greater<int>());
			break;
		}
		case 1: {
			sort(a+q, a+n+1);
			break;
		}
		}
	}
	for (int i = 1; i <= n; i++)
		printf("%d ", a[i]);
	return 0;

#include <iostream>

using namespace std;

const int N = 100010;
pair<int, int> stk[N];
int ans[N];

int main() {
	int n, m, top = 0;
	cin >> n >> m;
	while (m--) {
		int p, q;
		cin >> p >> q;
		if (p == 0) {
			while (top && stk[top].first == 0) {
				q = max(q, stk[top--].second);
			}
			while (top >= 2 && stk[top - 1].second <= q) {
				// 如果当前操作比上一次相同操作的范围要大,那此次操作的前两次操作都将被无效化 
				top -= 2;
			}
			stk[++top] = {0, q};
		} else if (top) {
			while (top && stk[top].first == 1) {
				q = min(q, stk[top--].second);
			}
			while (top >= 2 && stk[top - 1].second >= q) {
				// 如果当前操作比上一次相同操作的范围要大,那此次操作的前两次操作都将被无效化 
				top -= 2;
			}
			stk[++top] = {1, q};
		}
	}
	int left = 1, right = n, k = n;
	for (int i = 1; i < top + 1; i++) {
		if (stk[i].first == 0) {
			while (right > stk[i].second && left < right + 1) {
				ans[right--] = k--;
			}
		} else {
			while (left < stk[i].second && left < right + 1) {
				ans[left++] = k--;
			}
		}
		if (left > right) {
			break;
		}
	}
	if (top % 2) {
		while (left < right + 1) {
			ans[left++] = k--;
		}
	} else {
		while (left < right + 1) {
			ans[right--] = k--;
		}
	}
	for (int i = 1; i < n + 1; i++) {
		cout << ans[i] << " ";
	}
	return 0;
}
#include<bits/stdc++.h>
#define NMAX 100001 //最后多一个元素用来取地址给reverse用
//n:new
#define nd 0 //新元素类型为左递减
#define nu 1 //新元素类型为右递增
//d:down,u:up
int d[NMAX+1]={NMAX};//左递减操作序列,用大值托底(但这不算一次操作)
int u[NMAX+1]={0,1};//右递增操作序列,用小值托底(这个算一次操作)
//sd:sizeofDown
int sd=0,su=1;//左递减操作序列、右递增操作序列的大小,认为右递增序列中有一个元素1,因为序列最初是从1开始右递增的,可认为是第一次操作的结果
int N,T;//数字序列长度,操作次数
int A[NMAX+1];//保存数字序列
using namespace std;
int main(){
    cin >> N >> T;
    //v:value
    int type,v;
    while(T--){
        cin >> type >> v;
        if(type==nd){//如果是左递减操作
            if(v>=d[sd]){//撤回无用操作
                while(v>=d[sd])sd--;
                ++sd,su=sd,d[sd]=v;
            }else if(sd<su){//不能撤回就添加新操作(连续较小值的同种操作被sd<su吸收了)
                ++sd,d[sd]=v;
            }
        }else{
            if(v<=u[su]){//同上
                while(v<=u[su])su--;
                ++su,sd=su-1,u[su]=v;
            }else if(sd==su){
                ++su,u[su]=v;
            }
        }
    }
    for(int i=1;i<=N;++i){//初始值
        A[i]=i;
    }
    //p:pointer,u:up,d:down
    int pu=1;//现在从右递减的第一步开始执行操作
    int pd=1;
    while(pu<su){
        if(u[pu]<d[pd])//之前没考虑过m,n相撞的情况,在这里要避免
            reverse(&A[u[pu]],&A[d[pd]+1]);
        ++pu;
        if(u[pu]<d[pd])
            reverse(&A[u[pu]],&A[d[pd]+1]);
        ++pd;
    }
    if(su==sd){//如果两个大小一样则还差一步操作
        if(u[pu]<d[pd])
            reverse(&A[u[pu]],&A[d[pd]+1]);
    }
    for(int i=1;i<=N;++i){
        cout << A[i] << ' ';
    }
    cout << endl;
    return 0;
}

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>

using namespace std;

const int N = 100005;
pair<int,int> s[N];
int ret[N];
int n,m;

int main(){
    cin>>n>>m;
    int top=0;
    int k=n;
    for(int i=0;i<m;i++){
        int p,q;
        cin>>p>>q;
        //0 是 1->q降序排列
        if(!p){
            while(top&&s[top].first==0)
                q=max(q,s[top--].second);
            while(top>=2&&s[top-1].second<=q)
                top-=2;
            s[++top]={0,q};
        }
        else if(top){
            while(top&&s[top].first==1)
                q=min(q,s[top--].second);
            while(top>=2&&s[top-1].second>=q)
                top-=2;
            s[++top]={1,q};
        }
    }
    int l=1,r=n;
    for(int i=1;i<=top;i++){
        if(s[i].first==0)
            while(l<=r&&r>s[i].second)
                ret[r--]=k--;
        else
            while(l<=r&&l<s[i].second)
                ret[l++]=k--;
        if(l>r)
            break;
    }
    if(top%2)
        while(l<=r)
            ret[l++]=k--;
    else
        while(l<=r)
            ret[r--]=k--;
    for(int i=1;i<=n;i++)
        cout<<ret[i]<<" ";
    return 0;
}

参考博客

 2021年第十二届蓝桥杯 - 省赛 - C/C++大学B组 - I.双向排序_Alex_996的博客-优快云博客_第十二届蓝桥杯双向排序https://blog.youkuaiyun.com/weixin_43336281/article/details/122315761?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164753734816782092975074%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=164753734816782092975074&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-2-122315761.142%5Ev2%5Earticle_score_rank,143%5Ev4%5Econtrol&utm_term=%E5%8F%8C%E5%90%91%E6%8E%92%E5%BA%8F%E3%80%90%E7%AC%AC%E5%8D%81%E4%BA%8C%E5%B1%8A%E3%80%91%E3%80%90%E7%9C%81%E8%B5%9B%E3%80%91%E3%80%90C%E7%BB%84%E3%80%91&spm=1018.2226.3001.4187

 蓝桥杯2021年第十二届省赛-双向排序_9898zy998的博客-优快云博客_蓝桥杯双向排序https://blog.youkuaiyun.com/zy98zy998/article/details/122323706?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164753734816782092990278%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=164753734816782092990278&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-6-122323706.142%5Ev2%5Earticle_score_rank,143%5Ev4%5Econtrol&utm_term=%E5%8F%8C%E5%90%91%E6%8E%92%E5%BA%8F%E3%80%90%E7%AC%AC%E5%8D%81%E4%BA%8C%E5%B1%8A%E3%80%91%E3%80%90%E7%9C%81%E8%B5%9B%E3%80%91%E3%80%90C%E7%BB%84%E3%80%91&spm=1018.2226.3001.4187 第十二届蓝桥杯B组省赛双向排序题解_Nervous_46216553的博客-优快云博客https://blog.youkuaiyun.com/weixin_46216553/article/details/123094947?ops_request_misc=&request_id=&biz_id=102&utm_term=%E5%8F%8C%E5%90%91%E6%8E%92%E5%BA%8F%E3%80%90%E7%AC%AC%E5%8D%81%E4%BA%8C%E5%B1%8A%E3%80%91%E3%80%90%E7%9C%81%E8%B5%9B%E3%80%91%E3%80%90C%E7%BB%84%E3%80%91&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-1-123094947.142%5Ev2%5Earticle_score_rank,143%5Ev4%5Econtrol&spm=1018.2226.3001.4187

关于第十二届蓝桥杯Scratch初级的比资料、参指南、题目以及获奖名单的信息如下: ### 比资料 对于参与此类竞的学生而言,准备阶段获取官方发布的比资料至关重要。这些资料通常涵盖了编程环境的要求、评分标准以及其他注意事项等内容[^1]。 ### 参指南 参指南会详细介绍事流程、作品提交方式及时间安排等重要事项。学生需按照指南中的规定完成报名并按时上传自己的项目文件。此外,指南还可能提供一些创作建议来帮助选手更好地发挥创意和技术水平。 ```python # 示例代码用于说明如何解析JSON格式的参指南文档(假设) import json def parse_contest_guide(json_file_path): with open(json_file_path, 'r', encoding='utf-8') as file: guide_data = json.load(file) # 假设json结构中有'rules','submission_process','tips' rules = guide_data.get('rules') submission_process = guide_data.get('submission_process') tips = guide_data.get('tips') return { "Rules": rules, "Submission Process": submission_process, "Tips": tips } ``` ### 比题目 具体的比题目会在正式开后公布给所有注册成功的队伍或个人。这类题目往往围绕着特定主题设计多个挑战任务,鼓励孩子们运用所学知识解决问题的同时培养逻辑思维能力与创新能力。 ### 获奖名单 获奖名单一般在评审结束后由主办方统一发布,在官方网站上可以查询到最终的成绩排名情况。这不仅是对优秀作品的认可,也为其他参与者提供了学习的机会和方向指引。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Prudento

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值