嘘~ 正在从服务器偷取页面 . . .

UOJ174 新年的破栈 题解


UOJ174 新年的破栈 题解

题目链接:#174. 新年的破栈

题意

在这新年的第一天,神族首领 cxy 自然是要接受来自宇宙各国的朝贡的。在种类繁多的礼品中, q779 送来的栈引起了她的注意——她发现这个栈的大小正好适合来装她的核弹。

神族首领 cxy 有 \(n\) 个核弹,编号为 \(i\) 的核弹的威力是 \(A_i\),而且任意两颗核弹的威力都是不同的。现在她想用这个栈来整理这些核弹,每时每刻她可以进行下面三种操作中的一种:

  1. 入栈:如果当前还有核弹没有被放入过栈中,那么就把剩下的核弹中编号最小的放到栈中(作为新的栈顶)。
  2. 出栈:如果当前栈中有核弹,那么就把栈顶(即栈中最后被放入的)的核弹取出来。
  3. 打开阀门:如果当前栈中有核弹,那么就把栈底(即栈中最先被放入的)的核弹取出来。

在所有核弹都从栈中取出后, cxy 按照核弹出栈的时间顺序排成一排,再把这些核弹的威力记录下来,这样就得到了一个数列 \(B\)。现在 cxy 想让这个数列的字典序尽可能的小,但是因为她日理万机,没有时间来想这种简单的小问题,于是她就让你来帮她求出字典序最小的数列 \(B\)

对于两个长度为 \(n\) 的数列 \(a\)\(b\)\(a\) 的字典序小于 \(b\) 当且仅当存在一个整数 \(k \in [1,n]\) 满足 \(a_{i} = b_{i}(1 \leq i < k)\)\(a_k < b_k\)

输入格式

第一行一个正整数 \(T\),表示数据组数。

对于每组数据,第一行包含一个正整数 \(n\)

接下来一行 \(n\) 个正整数 \(A_1, \dots, A_n\)

输出格式

对于每组数据,输出一行 \(n\) 个正整数,表示字典序最小的数列 \(B\)

数据范围

对于所有数据,保证 \(1 \leq T \leq 5,~1\le n \le 10^5 ,~1 \leq A_i \leq 10^9\)

模拟了一会发现这东西貌似可以贪心。结果推了几组全是1开头的然后假了

首先可以发现,无论顺序是怎样的, \(A_0\) 一定在答案的第一项( \(A_0 = \min{A_i}\))。

因为只需要不停地入栈直到遇到 \(A_0\) ,然后把 \(A_0\) 弹出,总能得到第一项为 \(A_0\) 的答案。

考虑第二项,它一定是以下三种情况的最小值:

  • 选择此时的栈顶元素
  • 选择此时的栈底元素
  • 继续入栈,直到遇到一个极小值。

可以发现重复这个过程就能找到答案。

考虑如何实现。首先这个栈其实就是个双端队列,直接维护即可。

然后这个极小值其实就是后缀最小值,可以预处理出来。其他直接模拟即可

时间复杂度 \(\mathcal{O}(n)\)

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(1e5+15))

int n,st,en,a[N],mn[N],q[N];
void solve()
{
    cin >> n; mn[n+1] = INF; st=en=0;
    for(int i=1; i<=n; i++) cin >> a[i];
    for(int i=n; i; i--) mn[i] = min(a[i], mn[i+1]);
    for(int i=1,j=1; i<=n; i++)
        if(st < en && (q[st+1] < mn[j] || q[en] < mn[j]))
        { cout << (q[st+1] < q[en] ? q[++st] : q[en--]) << " \n"[i==n]; }
        else
        {
            cout << mn[j] << " \n"[i==n];
            for(; a[j] != mn[j]; j++) q[++en] = a[j]; ++j;
        }
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    int Q; cin >> Q; while(Q--) solve();
    return 0;
}

参考文献

[1] https://yhx-12243.github.io/OI-transit/records/uoj174.html


文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录