双栈排序(二分图染色+模拟)
Posted greengenius
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了双栈排序(二分图染色+模拟)相关的知识,希望对你有一定的参考价值。
题目链接 https://www.luogu.org/problemnew/show/P1155
一开始我还以为能直接模拟=-=,太天真了...写了好久对了3个点...看了题解之后恍然大悟,先二分图匹配一下确定每个点在哪个栈里头再模拟会轻松很多。可怎么建边呢?
我们先从单栈排序开始:
可以的出的是,对于i,j,若存在k使得i<j<k,且A[k]<A[i]<A[j]的时候,是一定不能单栈排序的
就像3 4 1这样的数,因为要保证小的先出来,
我们可以在这样的i,j间建边,用f[i]存i之后最小的数,这样就可以把复杂度降到n的平方
之后就可以二分图染色了=-=,染色时要注意1-n不一定时联通的,所以要for一遍把所有都染掉
然后就是模拟了=-=字典序有点恶心,但只要时刻保证先出来在进去,先考虑s1,再考虑s2就可以了
代码:
#include<cstdio> #include<cstdlib> #include<stack> #include<queue> #include<cstring> using namespace std; const int N=1010; int f[N],A[N]; struct node{ int nu,ne; }edge[N*N]; int tot,n; int col[N],head[N],belong[N]; char ans[N*2]; bool vis[N]; void add(int a,int b) { edge[++tot].nu=b; edge[tot].ne=head[a]; head[a]=tot; } bool bfs(int st) { queue<int>q; q.push(st); col[st]=1; vis[st]=true; while(!q.empty()) { int a=q.front(); q.pop(); for(int i=head[a];i!=-1;i=edge[i].ne) { int k=edge[i].nu; if(col[k]==col[a])return false; if(vis[k]) continue; vis[k]=true; col[k]=col[a]==1?2:1; q.push(k); } } return true; } int main() { memset(head,-1,sizeof(head)); stack<int>s1,s2; int bj=1,cnt=0; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&A[i]); memset(f,0x3f,sizeof(f)); A[n+1]=1e7; for(int i=n;i>=1;i--) f[i]=min(f[i+1],A[i]); for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) if(A[j]>A[i]&&A[i]>f[j+1]) add(A[i],A[j]),add(A[j],A[i]); for(int i=1;i<=n;i++) if(!col[A[i]]) if(!bfs(A[i])) return printf("0 "),0; for(int i=1;i<=n;i++) { if(col[A[i]]==1) belong[A[i]]=1; if(col[A[i]]==2) belong[A[i]]=2; } for(int i=1;i<=n;i++) { int a=belong[A[i]]; while(!s1.empty()&&s1.top()==bj) { bj++; s1.pop(); ans[++cnt]=‘b‘; } while(!s2.empty()&&s2.top()==bj) { bj++; s2.pop(); ans[++cnt]=‘d‘; } if(a==1) { s1.push(A[i]); ans[++cnt]=‘a‘; } if(a==2) { s2.push(A[i]); ans[++cnt]=‘c‘; } } while(!s1.empty()&&!s2.empty()) { if(s1.top()<s2.top()) { s1.pop(); ans[++cnt]=‘b‘; } else { s2.pop(); ans[++cnt]=‘d‘; } } while(!s1.empty())s1.pop(),ans[++cnt]=‘b‘; while(!s2.empty())s2.pop(),ans[++cnt]=‘d‘; for(int i=1;i<=cnt;i++) printf("%c ",ans[i]); return 0; }
以上是关于双栈排序(二分图染色+模拟)的主要内容,如果未能解决你的问题,请参考以下文章