洛谷 P5462 X龙珠

链接

题目描述

“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;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值