题目描述
“X龙珠”是一款益智小游戏。游戏中有 n(2|n)n(2∣n) 个编号互不相同龙珠按照给定的顺序排成一个队列,每个龙珠上面都有一个编号。每次操作时,选择并取出龙珠队列中相邻的两个龙珠,放到目标队列的末尾(目标队列最开始是空的,且这两个龙珠的前后顺序不变),然后去除原龙珠队列的空隙。反复多次,直到原龙珠队列为空。可见,因为决策不一样导致目标队列顺序不一样。现在请求出所有方案中、目标队列字典序最大的方案。只需要给出目标队列即可。
例如,当原龙珠队列是 [1,3,2,4] 时,可以先取出 3 和 2,此时目标队列是 [3,2],原龙珠队列是 [1,4];再将剩下两个龙珠放入目标队列,得到目标队列是 [3,2,1,4]
输入格式
第一行,一个整数 n。
接下来一行,每行 n 个整数,表示原龙珠队列的编号。
输出格式
一行,n 个整数。
输入输出样例
输入
4
3 1 4 2
输出
4 2 3 1
输入
6
6 5 4 1 3 2
输出
6 5 4 1 3 2
说明/提示
对于 20% 的数据,n≤10。
对于 60% 的数据,n≤10^3。
对于 100% 的数据,n≤10^5,龙珠编号不超过 n。
思路
用pre数组和next数组分别维护当前位置前一个数的位置和后一个数的位置,
pre[1]=-1,next[n]=-1;
用set维护递增的序列,用pos数组维护某个值的位置。
首先从set中取一个最大值,判断最大值后面是不是还有数字,如果没有,那么取一个次大的。
我们知道要取的第一个数之后,根据pos数组得到这个数的下标记为index,然后利用Next数组得到下一个数字的下标记为nindex.
用vis标记当前这个数有没有被拿走,如果是0那么没被拿掉,否则被拿掉了.
标记这两个数被拿走了,将这两个数放入队列中,从set中删除掉这两个数字。接下来更新pre数组和next数组。
next要更新的位置应该是pre[index],pre数组要更新的位置是next[nindex]。
code
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int pre[N],Next[N],arr[N],pos[N],vis[N],n;
set<int>s;
set<int>::iterator it;
queue<int>q;
void getNext(int index)
{
int x=index;
while(x!=-1&&vis[Next[x]]==1)
{
x=Next[x];
}
if(x==-1) Next[index]=-1;
else Next[index]=Next[x];
}
void getpre(int index)
{
int x=index;
while(x!=-1&&vis[pre[x]]==1)
{
x=pre[x];
}
if(x==-1) pre[index]=-1;
else pre[index]=pre[x];
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&arr[i]);
pos[arr[i]]=i;
s.insert(arr[i]);
i==1?pre[i]=-1:pre[i]=i-1;
i==n?Next[i]=-1:Next[i]=i+1;
}
for(int i=1;i<=n/2;i++)
{
it=s.end();
int index,nindex=-1,Max;
while(nindex==-1)
{
it--;
Max=*it;
index=pos[Max];
nindex=Next[index];
}
// printf("%d %d\n",arr[index],arr[nindex]);
s.erase(arr[index]),s.erase(arr[nindex]);
q.push(arr[index]),q.push(arr[nindex]);
vis[index]=vis[nindex]=1;//标记为已经消失
if(pre[index]!=-1) getNext(pre[index]);
if(Next[nindex]!=-1) getpre(Next[nindex]);
}
while(!q.empty())
{
printf("%d ",q.front());
q.pop();
}
return 0;
}