zrmpaul Loves Array

52 篇文章 1 订阅

https://www.luogu.com.cn/problem/T145688?contestId=33886


 

题目背景

原题面:

\color{gray}\text{zrmpaul}zrmpaul has an array consisting of nn integers: a_1,a_2,...,a_na1​,a2​,...,an​. The initial value of a_iai​ is i(1\le i\le n)i(1≤i≤n). There are mm operations, including four types as follows.

Type 11: 1 sort the array.
Type 22: 2 sort the array and reverse it.
Type 33: 3 x y swap a_x,a_yax​,ay​. It is guaranteed that xx is not equal to yy, and 1\leq x ,y \leq n1≤x,y≤n.
Type 44: 4 reverse the array.

You need to output the array after mm operations.

First line with two intergers n,m(1\leq n,m\leq 10^6)n,m(1≤n,m≤106).

Next mm lines are the operations.

One line, nn numbers, the array.

题目描述

小 Z 有一个下标从 11 开始并且长度为 nn 的序列,初始时下标为 ii 位置的数字为 ii。有 mm 个操作,每个操作会是以下四种之一。

  • 1 对序列从小到大进行排序。
  • 2 对序列从小到大进行排序后将其翻转,(译者注:就是从大到小排序)。
  • 3 x y 将下标为 x,yx,y 的数交换位置。保证 x\neq yx​=y 且 1\le x,y\le n1≤x,y≤n。
  • 4 将序列翻转。

你要输出在 mm 次操作后的序列。

输入格式

第一行两个整数 n,mn,m ,表示序列的长度以及操作的数量。

接下来 mm 行,每行一个操作。保证操作合法。

输出格式

一行包含 nn 个整数,表示操作后的序列。

输入输出样例

输入 #1复制

5 5
1
2
3 2 4
4
3 1 5

输出 #1复制

5 4 3 2 1

说明/提示

【数据范围】

【本题采用捆绑测试】

subtask 1(24pts): 1\leq n,m\leq 2 \times 10^31≤n,m≤2×103 。

subtask 2(13pts): 没有操作三。

subtask 3(63pts): 1\leq n,m\leq 10^61≤n,m≤106 。

【样例解释】

序列经过的操作为:

1, 2, 3, 4, 51,2,3,4,5
1, 2, 3, 4, 51,2,3,4,5
5, 4, 3, 2, 15,4,3,2,1
5, 2, 3, 4, 15,2,3,4,1
1, 4, 3, 2, 51,4,3,2,5
5, 4, 3, 2, 15,4,3,2,1


思路:当然第一眼的时候思路是暴力辣。然后看了看范围肯定只能拿pretest1的分。然后就接着想。

发现如果3,4的后面有1或者2,那么这时候3,4的操作都是抵消的,就是说这些3的操作或者4的操作都是无效的。知道了这一点之后你会发现如果后面没有3,那么1,2,4的操作就只有x=0(正序),x=1(反序)之间来回变换,这里直接O(1)就可以了,不用那些sort的nlogn。

当时卡我的reverse操作,比如现在进行了3操作,接下来有4操作,再有3操作,再有4操作,这时候的swap和reverse怎么处理呢?当时想了下应该是把l和r根据长度减下换了,但是又觉得不等价。于是往其他方向瞎想gg。

正解就是比如现在是x=0,那么换就直接换l和r的两个数字,如果这时候出了4反序,无所谓标记一下x=1,再出了3交换,这时候交换n-l+1和n-r+1的地方就是等价的,若再出4,就标记x=0,这时候如果交换就换l和r的。这样就等价了...(555我太菜了

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=1e6+100;
typedef long long LL;
LL a[maxn];
LL l[maxn],r[maxn],op[maxn];
int main(void)
{
  cin.tie(0);std::ios::sync_with_stdio(false);
  LL n,m;cin>>n>>m;
  for(LL i=1;i<=n;i++) a[i]=i;
  for(LL i=1;i<=m;i++)
  {
  	cin>>op[i];
  	if(op[i]==3) cin>>l[i]>>r[i];
  	else l[i]=r[i]=0;
  }
  LL pos=1;
  for(LL i=m;i>=1;i--)
  {
  	if(op[i]==1||op[i]==2) {pos=i;break;}
  }
  LL x=0;//正序 
  if(op[pos]==1) x=0;
  else x=1-x;
  for(LL i=pos+1;i<=m;i++)
  {
  	 if(op[i]==3)
	 {
	 	if(x==0) swap(a[l[i]],a[r[i]]);
		else swap(a[n-l[i]+1],a[n-r[i]+1]);  	
	 }	
	 else x=1-x;
  }  
  if(x==0)
  {
  	for(LL i=1;i<=n;i++) cout<<a[i]<<" ";
  	cout<<endl;
  }
  else{
  	for(LL i=n;i>=1;i--) cout<<a[i]<<" ";
  	cout<<endl;
  }
return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值