初见安~这里是传送门:洛谷P1155 双栈排序
题解
一眼贪心。【然后就WA了70分。啪。】
其实我们看第一组测试的数据【考试的时候作为样例下放】,也就是:
就可以发现一件事情——到了插入7的时候我们选择的是stc2而不是stc1,否则无解。【stc:stack】
而多数时候,在没有这种限制的情况下我们果断选择放到stc1里面去。
所以我们就从【无解】的角度切入。
当存在且的时候,i和j不可能出现在同一个栈里面。
这个结论你想到了你就想到了,没想到就炸了。正确性也显然——因为保证输出序列单调递增,所以为了让a[k]先出去,a[i]必须进栈等,同理a[j]也要进栈,所以如果a[i]和a[j]进同一个栈,a[i]就会被a[j]堵在里面出不来了。如果a[k]>a[i]就不存在了,因为a[i]可以先出来。
至此,通过这个结论,假设一定有解的话,被这个结论限制的点一定可以被划分为两个集合,其余的点我们自动放进stc1。这样一来我们就已经分好组了,剩下的直接贪心取就可以了。
模拟stc的时候明显要保证单调递减。
对于取的操作,在已经分组的条件下我们的优先级:
1.如果是分到了stc1:
如果stc1的栈顶元素小于当前数,那就pop出去【b】
否则 放进去【a】
2.如果是分到了stc2:
如果stc1的栈顶元素能出去,那就先出去【b】
否则
如果stc2的栈顶元素小于当前数,pop出去【d】
否则 放进去【c】
以上就是所有的思路了。大致是二分图染色+贪心模拟。
上代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define maxn 1005
using namespace std;
typedef long long ll;
int read() {
int x = 0, f = 1, ch = getchar();
while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
while(isdigit(ch)) x = (x << 1) + (x << 3) + ch - '0', ch = getchar();
return x * f;
}
int n, a[maxn], minn[maxn], stc1[maxn], stc2[maxn], top1 = 0, top2 = 0, now = 1, cnt = 0;
char ans[maxn << 2];
int col[maxn];
signed main() {
memset(col, -1, sizeof col);
n = read(); stc1[0] = stc2[0] = 0x3f3f3f3f; minn[n + 1] = n + 1;
for(int i = 1; i <= n; i++) a[i] = read();
for(int i = n; i > 0; i--) minn[i] = min(minn[i + 1], a[i]);
for(int i = 1; i <= n; i++) for(int j = i + 1; j <= n; j++) if(a[i] < a[j] && a[i] > minn[j + 1]) {
if(col[i] == -1 && col[j] == -1) col[i] = 0, col[j] = 1;//染色
else if(!~col[i]) col[i] = col[j] ^ 1;
else if(!~col[j]) col[j] = col[i] ^ 1;
else if(col[i] == col[j]) {puts("0"); return 0;}
}
for(int i = 1; i <= n; i++) {
if(!~col[i]) col[i] = 0;//没有受到限制,自动归为stc1
if(!col[i]) {//下面就是上面说的贪心模拟
while(stc1[top1] == now && a[i] > stc1[top1]) top1--, now++, ans[++cnt] = 'b';
stc1[++top1] = a[i]; ans[++cnt] = 'a';
}
else {
while(stc1[top1] == now) top1--, now++, ans[++cnt] = 'b';
while(stc2[top2] == now && a[i] > stc2[top2]) top2--, now++, ans[++cnt] = 'd';
stc2[++top2] = a[i], ans[++cnt] = 'c';
}
}
while(now <= n) {//记得处理还在栈里面的元素
if(stc1[top1] == now) top1--, ans[++cnt] = 'b';
else top2--, ans[++cnt] = 'd';
now++;
}
for(int i = 1; i <= cnt; i++) printf("%c ", ans[i]);
return 0;
}
/*
10
10 2 8 1 7 9 3 4 5 6
a a c a b b c a a b a b a b a b d d b b
*/
迎评:)
——End——