P1155 [NOIP 2008 提高组] 双栈排序
题目描述
Tom 最近在研究一个有趣的排序问题。如图所示,通过 2 2 2 个栈 S 1 S_1 S1 和 S 2 S_2 S2,Tom 希望借助以下 4 4 4 种操作实现将输入序列升序排序。
- 操作 a \verb!a! a:将第一个元素压入栈 S 1 S_1 S1。
- 操作 b \verb!b! b:将 S 1 S_1 S1 栈顶元素弹出至输出序列。
- 操作 c \verb!c! c:将第一个元素压入栈 S 2 S_2 S2。
- 操作 d \verb!d! d:将 S 2 S_2 S2 栈顶元素弹出至输出序列。
如果一个 1 ∼ n 1\sim n 1∼n 的排列 P P P 可以通过一系列合法操作使得输出序列为 ( 1 , 2 , ⋯ , n − 1 , n ) (1,2,\cdots,n-1,n) (1,2,⋯,n−1,n),Tom 就称 P P P 是一个“可双栈排序排列”。例如 ( 1 , 3 , 2 , 4 ) (1,3,2,4) (1,3,2,4) 就是一个“可双栈排序序列”,而 ( 2 , 3 , 4 , 1 ) (2,3,4,1) (2,3,4,1) 不是。下图描述了一个将 ( 1 , 3 , 2 , 4 ) (1,3,2,4) (1,3,2,4) 排序的操作序列: a,c,c,b,a,d,d,b \texttt {a,c,c,b,a,d,d,b} a,c,c,b,a,d,d,b。
当然,这样的操作序列有可能有几个,对于上例 ( 1 , 3 , 2 , 4 ) (1,3,2,4) (1,3,2,4), a,b,a,a,b,b,a,b \texttt{a,b,a,a,b,b,a,b} a,b,a,a,b,b,a,b 是另外一个可行的操作序列。Tom 希望知道其中字典序最小的操作序列是什么。
输入格式
第一行是一个整数 n n n。
第二行有 n n n 个用空格隔开的正整数,构成一个 1 ∼ n 1\sim n 1∼n 的排列。
输出格式
共一行,如果输入的排列不是“可双栈排序排列”,输出 0
。
否则输出字典序最小的操作序列,每两个操作之间用空格隔开,行尾没有空格。
输入输出样例 #1
输入 #1
4
1 3 2 4
输出 #1
a b a a b b a b
输入输出样例 #2
输入 #2
4
2 3 4 1
输出 #2
0
输入输出样例 #3
输入 #3
3
2 3 1
输出 #3
a c a b b d
说明/提示
30 % 30\% 30% 的数据满足: n ≤ 10 n\le10 n≤10。
50 % 50\% 50% 的数据满足: n ≤ 50 n\le50 n≤50。
100 % 100\% 100% 的数据满足: n ≤ 1000 n\le1000 n≤1000。
2021.06.17 加强 by SSerxhs。hack 数据单独分为一个 subtask 防止混淆。
noip2008 提高第四题
方法有漏洞,仅供参考
提供一个hack数据
(
7
5 7 2 4 1 6 3
代码输出无解,但这个序列是有解的,关键在于把 2 放在第二个栈而非贪心的第一个,把2放在第二个栈才能使1,2,3,4,5,能出来,不然会被6卡住。
)
核心思路
- 栈操作模拟
- 栈 s1 用于直接压入当前元素,并检查是否可以弹出(若栈顶元素等于当前期望值 sj)。
- 栈 s2 用于处理无法直接压入 s1 的元素,并通过 check 函数验证后续操作是否合法。
- 辅助栈 s3 用于临时存储 s2 的元素以验证序列合法性。
- 合法性检查(check函数)
- 检查栈 s2 是否可以按期望顺序弹出元素(从 sj 开始连续递增)。
- 遍历后续未处理的元素,确保没有更小的元素会阻塞排序。
- 操作序列生成
- 根据当前元素和栈状态生成操作序列(‘a’、‘b’、‘c’、‘d’),若无法完成排序则输出 0。
详细代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e3+5;
int n,a[N],sj;
char b[N*4];
stack<int>s1,s2,s3;
bool check (int k)
{int _=sj;while (!s2.empty()&& s2.top()==_++)s3.push(s2.top()),s2.pop();if(s2.empty()){while (!s3.empty ()) s2.push(s3.top()),s3.pop();return 1;}for (int i=k+1;i<=n;i++){if (a[i]<a[k]||a[i]<s2.top())continue;for(int j=i+1;j<=n;j++){if(a[j]<a[k]&&a[j]<s2.top()){while (!s3.empty ()) s2.push(s3.top()),s3.pop();return 0;}}break;}while (!s3.empty ())s2.push(s3.top()),s3.pop();return 1;
}
signed main()
{ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);cin>>n;for(int i=1;i<=n;i++)cin>>a[i];int js=1;sj=1;int tot=0;while(js<=n||(!s1.empty()||!s2.empty())){
// cout<<1;
// js++;while(1){bool flag=0;while(check(js)&&js<=n&&(s1.empty()||(!s1.empty()&&s1.top()>a[js]))){s1.push(a[js]);js++;b[++tot]='a';flag=1;}while(!s1.empty()&&s1.top()==sj){b[++tot]='b';s1.pop();sj++;flag=1;}if(!flag)break;}while(!s2.empty()&&s2.top()==sj){b[++tot]='d';s2.pop();sj++;}if(!s1.empty()&&!s2.empty()&&s1.top()<a[js]&&s2.top()<a[js]){cout<<"0";return 0;}if(js<=n&&((!s2.empty()&&s2.top()>a[js])||s2.empty())){s2.push(a[js]);js++;b[++tot]='c';}}for(int i=1;i<=tot;i++)cout<<b[i]<<" ";return 0;
}