洛谷P1155双栈排序

洛谷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;
}

猜你喜欢

转载自www.cnblogs.com/JWizard/p/12323182.html