洛谷P1155双栈排序
题目链接:https://www.luogu.com.cn/problem/P1155
根据出栈顺序为升序可以知道,应该维护单调栈,使得栈顶元素小于栈底元素,也就是一个从栈顶到栈底单增的栈
现在考虑a[i]能不能进栈1:
试想这样一个问题,假如序列中存在a[i]<aj,如果按照序列的顺序,将a[i],a[j]入栈,那是一定不行的,因为出栈顺序为a[j],a[i],非升序
但是i,j并不一定相邻,我们可能在某个位置k:i<k<j时,让a[i]能出栈了,这时候a[i],a[j]就可以进同一个栈了
什么时候a[i]能进栈1,首先必须要a[i]<s1.top():
(1) 栈2为空。
因为此时就算存在i<j<k,a[k]<a[i]<a[j],也可以让a[j]进入栈2,有了解决方案
(2) 栈2非空,且序列中不存在i<j<k,a[k]<a[i]<a[j], a[j]>s2.top()
if a[i]->s1
if a[j]->s1
because a[k]<a[i], so s1中有a[i]<a[j],且a[i]出栈晚于a[j],排除
if a[j]->s2
s2非空,分析一下什么元素会进s2.
假设s1和s2栈顶元素相等(当然题中不可能发生)那应该是弹s1较优,因为字典序更小。
假设s1栈顶元素>s2栈顶元素,不可能,因为字典序也不是最优
所以s2.top()>s1.top(),又因为a[j]>s2.top(),
所以a[j]>s2.top()>s1.top()>a[i]>a[k]
翻译一下这是啥意思呢,就是在a[k]未弹出时,a[j]没有地方可去,这是不行的
所以写个判断函数,贪心解决就行了。
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
int n,a[N],now=1;
vector<char> ans;
stack<int> s,t;
void push1(int u){s.push(u);ans.push_back('a');}
void push2(int u){t.push(u);ans.push_back('c');}
void pop1(){s.pop();ans.push_back('b');}
void pop2(){t.pop();ans.push_back('d');}
bool check(int k)//a[k]<s.top()
{
if(t.empty()) return 1;
int i,j;//k<i<j
for(i=k+1;i<=n;i++) if(a[i]>a[k]&&a[i]>t.top()) break;
for(j=i+1;j<=n;j++) if(a[j]<a[k]) return 0;
return 1;
}
int main()
{
scanf("%d",&n);
int cnt=1;
s.push(1e4),t.push(1e4);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
bool ok=true;
for(int i=1;i<=(n<<1);i++)
{
if(s.top()==now) {pop1();now++;continue;}
if(t.top()==now) {pop2();now++;continue;}
if(cnt<=n&&a[cnt]<s.top()&&check(cnt)) {push1(a[cnt++]);continue;}
if(cnt<=n&&a[cnt]<t.top()) {push2(a[cnt++]);continue;}
ok=false;break;
}
if(ok)
{
for(int i=0;i<ans.size();i++)
if(i==0) putchar(ans[i]);
else printf(" %c",ans[i]);;
}
else puts("0");
return 0;
}