将一组数据分成两组,且组内不能冲突。考虑使用二分图。
我们来思考什么样的两个数不能存在于一个栈中。因为最后要求我们升序排序输出,所以在一个栈中的数字必定是降序。
那么当 \(i<j\) 时并且 \(p_i<p_j\)。\(i,j\) 便不能存在于同一个栈中吗?
显然不是,我们来看 \(P=\left [1,3,2,4\right ]\)。前两个数 \(1,3\) 是可以满足上文的情况的,但是他们可以存在在一个栈里面 。为什么会造成这种情况呢?我们发现数字 \(1\) 入栈后就可以直接弹,因为它后面没有比它小的数字了。
所以我们还要加一个附加条件。即当 \(i<j<k\) 且 \(p_k<p_i<p_j\) 满足时,\(i,j\) 不能共存于一个栈中。之后我们便在 \(i,j\) 之间建边,去做二分图即可。
之后我们考虑如何让字典序最小,观察到两个栈的操作是独立的,那么如果相邻的两个操作是一个栈插入,另一个栈弹出,那么可以交换位置,以此让字典序达到最小。
讲的很详细了,代码就不放注释了。
cpp
#include<bits/stdc++.h>
using namespace std;
const int N=1007;
int n,a[N],cnt=1,tot;
stack<int> s1,s2;
vector<int> G[N];
char ans[N*3];
bool vis[N],col[N];
void dfs(int u,int co){
// cout<<u<<' '<<co<<'\n';
vis[u]=1,col[u]=co;
for(auto v:G[u]){
if(vis[v]) {
if(col[v]==col[u]) {
cout<<0;
exit(0);
}
continue;
}
dfs(v,co^1);
}
}
int main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=n-1,x=a[n];i>1;i--){
for(int j=i-1;j>=1;j--){
if(a[j]<a[i]&&x<a[j]) G[a[j]].push_back(a[i]),G[a[i]].push_back(a[j]);
}
x=min(x,a[i]);
}
for(int i=1;i<=n;i++){
if(!vis[a[i]]) dfs(a[i],0);
}
// for(int i=1;i<=n;i++) cout<<col[i]<<' ';
// cout<<'\n';
for(int i=1;i<=n;i++){
if(col[a[i]]==0) ans[++tot]+='a',s1.push(a[i]);
else ans[++tot]+='c',s2.push(a[i]);
while((!s1.empty()&&s1.top()==cnt)||(!s2.empty()&&s2.top()==cnt)){
if(!s1.empty()&&s1.top()==cnt) ans[++tot]='b',s1.pop(),cnt++;
else ans[++tot]='d',s2.pop(),cnt++;
}
}
for(int i=tot-1;i>=1;i--){
for(int j=i;j<tot;j++){
if((ans[j]=='c'&&ans[j+1]=='b')||(ans[j]=='d'&&ans[j+1]=='a')) swap(ans[j],ans[j+1]);
else break;
}
}
for(int i=1;i<=tot;i++) cout<<ans[i]<<' ';
return 0;
}