题目描述
Tom最近在研究一个有趣的排序问题。如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序。
操作a
如果输入序列不为空,将第一个元素压入栈S1
操作b
如果栈S1不为空,将S1栈顶元素弹出至输出序列
操作c
如果输入序列不为空,将第一个元素压入栈S2
操作d
如果栈S2不为空,将S2栈顶元素弹出至输出序列
输入输出格式
输入格式:
输入文件twostack.in的第一行是一个整数n。
第二行有n个用空格隔开的正整数,构成一个1~n的排列。
输出格式:
输出文件twostack.out共一行,如果输入的排列不是“可双栈排序排列”,输出数字0;否则输出字典序最小的操作序列,每两个操作之间用空格隔开,行尾没有空格。
输入输出样例
输入样例#1:
【输入样例1】
4
1 3 2 4
【输入样例2】
4
2 3 4 1
【输入样例3】
3
2 3 1
输出样例#1:
【输出样例1】
a b a a b b a b
【输出样例2】
0
【输出样例3】
a c a b b d
说明
30%的数据满足: n<=10
50%的数据满足: n<=50
100%的数据满足: n<=1000
分析:
第一眼看过去,很简单啊,模拟一下就好了
只要遵循:
在栈里的元素一定是单调递减的
栈里相邻元素相差的越少越好,
优先选择第一个栈
实测:40分
这完全就是钻制度的空子。。。
好吧,说正经的
考虑a[i],a[j]两个元素不能进入同一个栈的条件.
注意,这里所说的”a[i],a[j]两个元素不能进入同一个栈“,
是自始至终不能进入一个栈,
即如果有解,那么a[i],a[j]一定进入过的栈不同.
条件:存在k使得i < j < k且a[k] < a[i] < a[j]
进栈顺序i->j->k
栈中的元素一定是单调减的
如果ta们在一个栈中,那么进栈顺序是j->i->k,与原命题矛盾
那知道了这个有什么用呢
我们可以知道元素两两能不能在一起,
如果i和j不能在一起,j和k不能在一起,i和k不能在一起,那原序列无解
我们把不能在一起的一对点之间连边
(突然觉得这蜜汁像关押罪犯,当有冲突时,就把边两端的点分配到不同的集合中去)
之后遍历一遍进行01染色
这样我们知道了进栈的状况,就可以直接模拟输出了
(直接上40分的骗分)
tip
按理说在处理冲突点对的时候是O(n^3)的复杂度,对于1000太大了,大神说要用dp优化一下,但是luogu数据实在是太耿直了,打的三方暴力就这样A了
简单说一下dp优化,
因为我们只要找到一个k满足就判定是冲突点对,
所以设f[i]表示i-n中的最小值
如果最小值都满足不了那就不可能了
这样可以把k的循环降到O(1)
这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
const int N=1010;
int n,a[N];
char s[N];
struct node{
int x,y,nxt;
};
node way[N<<1];
int st[N],tot=0,co[N],st1[N],st2[N];
void add(int u,int w)
{
tot++;
way[tot].x=u;way[tot].y=w;way[tot].nxt=st[u];st[u]=tot;
tot++;
way[tot].x=w;way[tot].y=u;way[tot].nxt=st[w];st[w]=tot;
}
void doit()
{
int i,j;
memset(co,-1,sizeof(co));
queue<int> q;
q.push(way[1].x);
co[way[1].x]=0;
while (!q.empty()) //染色
{
int r=q.front();
q.pop();
for (i=st[r];i;i=way[i].nxt)
{
if (co[way[i].y]==-1)
{
co[way[i].y]=(co[r]==0 ? 1:0);
q.push(way[i].y);
}
else if (co[way[i].y]==co[r])
{
printf("0\n");
return;
}
}
}
int t=-1,t1=0,t2=0,k=1;
for (i=1;i<=n;i++)
{
if (a[k]==i)
{
printf("a b ");k++;
continue;
}
if (st1[t1]==i)
{
printf("b "); t1--; continue;
}
if (st2[t2]==i)
{
printf("d "); t2--; continue;
}
while (a[k]!=i)
{
if (co[k]==0||co[k]==-1)
printf("a "),st1[++t1]=a[k];
else printf("c "),st2[++t2]=a[k];
k++;
}
printf("a b ");k++;
}
return;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
for (int i=1;i<n-1;i++) //i<j<k a[k]>a[i]>a[j]
for (int j=i+1;j<n;j++)
{
if (a[i]<a[j])
for (int k=j+1;k<=n;k++)
if (a[k]<a[i])
{
add(i,j);break;
}
}
doit();
return 0;
}