蓝桥杯 双向排序【省赛】【研究生组】

 

可以结合AcWing的视频讲解深入理解: AcWing 3419. 双向排序(蓝桥杯C++ AB组辅导课) - AcWing

C++解答:

#include<iostream>
#include<utility>
#include<algorithm>

using namespace std;

#define N 100010

pair<int, int> stack[N]; //存储可以执行的操作的栈

int ans[N];  // 存储答案 

int main()
{
	int n, m;
	cin>>n>>m;
	int a, b, top = 0;  //top栈顶 
	//需要明白的是,栈内最终存储的是前缀和后缀的交替操作,并且交集部分是递减的 
	while(m --)
	{
		cin>>a>>b;
		if(a == 0)  //前缀降序
		{
			// 将所有相连且相同的操作整合为一个,省略不必要操作
            // 同为前缀,操作坐标小的可以被操作坐标大的代替(内部排序可以被整体排序代替)
            // 同为后缀,操作坐标大的可以被操作左边小的代替
			while(top!=0 && stack[top].first==0)
			{
				b = max(b, stack[top].second);  //保留操作坐标大的 
				top--; //出栈 
			}
			// 若后缀操作前面的前缀操作比当前的前缀操作数小,可以将前、后缀操作均省略(内部排序可以被整体排序代替)
			while(top>=2 && stack[top-1].second<=b)
			{
				top = top - 2;  //出两次栈,相当于同时省略前面的一次前缀和一次后缀操作 
			}
			stack[++top] = make_pair(a, b); //入栈 
		}
		else  //后缀升序 
		{
			if(top != 0)  //第一步有意义的操作肯定是前缀降序(如果第一步是后缀升序,原始数列本来就是升序的) 
			{
				//后缀的情况同理 
				while(top!=0 && stack[top].first==1)
				{
					b = min(b, stack[top].second);
					top--;
				}
				while(top>=2 && stack[top-1].second>=b)
				{
					top = top - 2;
				}
				stack[++top] = make_pair(a, b);
			}
		}
	}
	int k = n;  //用于计数填空ans 
	int l=1, r=n;  //创建左右端点,记录已经排列的坐标
	for(int i=1; i<=top; i++)  //将栈从栈底到栈顶遍历一遍,把栈当作队列使用 
	{
		if(stack[i].first == 0)
		{
			// 若本操作为前缀,操作坐标之后的数就不会再被修改,即可确定进入答案数组
            // 后缀为升序,从后往前即为  k -- 操作
			while(r>stack[i].second && l<=r)
			{
				ans[r--] = k--;
			}
		}
		else
		{
			// 若本操作为后缀,操作坐标之前的数就不会再被修改,即可确定进入答案数组
            // 前缀为逆降,从前往后即为  k -- 操作
            while(l<stack[i].second && l<=r)
            {
            	ans[l++] = k--;
			}
		}
	}
	// 如果序列还没有被遍历完(中间重合部分),就通过考虑最后的操作是正序还是倒序将剩余的序列排好
    // 因为最先的操作只有是前缀才有效,所有操作均交替进行
    // 可以通过 top % 2 进行判断最后一项操作是什么
    // 如果 top % 2 == 1 ,最后一项是前缀,最后的部分是逆序
    //      top % 2 == 0 ,最后一项是后缀,最后的部分是正序
	if(top%2 == 0)
	{
		while(l<=r)
		{
			ans[r--] = k--;
		}
	}
	else
	{
		while(l<=r)
		{
			ans[l++] = k--;
		}
	}
	for(int i=1; i<=n; i++)
	{
		cout<<ans[i]<<" ";
	}
	return 0;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值