题面描述
Tom最近在研究一个有趣的排序问题。通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序。
操作a
如果输入序列不为空,将第一个元素压入栈S1
操作b
如果栈S1不为空,将S1栈顶元素弹出至输出序列
操作c
如果输入序列不为空,将第一个元素压入栈S2
操作d
如果栈S2不为空,将S2栈顶元素弹出至输出序列
如果一个1~n的排列P可以通过一系列操作使得输出序列为1, 2,…,(n-1), n,Tom就称P是一个"可双栈排序排列"。例如(1, 3, 2, 4)就是一个"可双栈排序序列",而(2, 3, 4, 1)不是。下图描述了一个将(1, 3, 2, 4)排序的操作序列:<a, c, c, b, a, d, d, b>
当然,这样的操作序列有可能有几个,对于上例(1, 3, 2, 4),<a, c, c, b, a, d, d, b>是另外一个可行的操作序列。Tom希望知道其中字典序最小的操作序列是什么。
思路
我们通过观察可以发现,
由于要最小字典序,我们要尽可能将数压入
S
1
S_1
S1。
那什么时候将数压入
S
2
S_2
S2呢?
我们设有
i
,
j
,
k
i,j,k
i,j,k这三个变量,满足
i
<
j
<
k
i<j<k
i<j<k,且
a
[
k
]
<
a
[
i
]
<
a
[
j
]
a[k]<a[i]<a[j]
a[k]<a[i]<a[j],
此时这种情况
i
,
j
i,j
i,j一定不能同时被压入同一个栈
反证法:
若
i
,
j
i,j
i,j压入同一个栈,
则
k
k
k要先出栈,所以
i
i
i就进栈后要等
k
k
k出栈才能出栈,
而无论
k
k
k在哪里,都无法让
i
i
i先于
j
j
j出栈。
故该命题不成立。
得证。
此时,我们易观察到,这就是
i
i
i与
j
j
j建边后,就是一个二分图。
若违背二分图规则,则不满足题意。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<stack>
using namespace std;
const int N=1e6+10;
const int M=1e3+10;
const int inf=1e9+10;
struct edge{int x,y,next;}a[N];int len,last[M];
void ins(int x,int y){a[++len].x=x,a[len].y=y;a[len].next=last[x];last[x]=len;}
int clr[M];bool bk;
int s[M],b[M],n;
void get(int x,int c)
{
clr[x]=c;
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(clr[y]==c){bk=false;return ;}
if(!clr[y])get(y,3-c);
}
}
void solve()
{
bk=true;
memset(clr,0,sizeof(clr));memset(b,0,sizeof(b));
len=0;memset(last,0,sizeof(last));scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&s[i]),b[i]=s[i];
b[n+1]=inf;
for(int i=n;i>=1;i--)if(b[i+1]<b[i])b[i]=b[i+1];
for(int i=1;i<=n;i++)
{
for(int j=i;j<=n;j++)
{
if(b[j+1]<s[i]&&s[j]>s[i])ins(i,j),ins(j,i);
}
}
for(int i=1;i<=n;i++)if(!clr[i])get(i,1);
if(!bk){puts("0");return ;}
stack<int>st1,st2;int cnt=1,num=1;
for(int i=1;i<=n;i++)
{
if(clr[i]==1)
{
st1.push(s[i]);
putchar('a');cnt++;
if(cnt<=2*n)putchar(' ');
}
else
{
st2.push(s[i]);
putchar('c');cnt++;
if(cnt<=2*n)putchar(' ');
}
while((!st1.empty()&&st1.top()==num)||(!st2.empty()&&st2.top()==num))
{
if(!st1.empty()&&st1.top()==num)
{
num++;st1.pop();
putchar('b');cnt++;
if(cnt<=2*n)putchar(' ');
}
else if(!st2.empty()&&st2.top()==num)
{
num++;st2.pop();
putchar('d');cnt++;
if(cnt<=2*n)putchar(' ');
}
}
}
puts("");
}
int main()
{
//freopen("input","r",stdin);
int t;scanf("%d",&t);
while(t--)solve();
return 0;
}