NOIP2008·洛谷·双栈排序

3 篇文章 0 订阅
2 篇文章 0 订阅

初见安~这里是传送门:洛谷P1155 双栈排序

    题解

一眼贪心。【然后就WA了70分。啪。

其实我们看第一组测试的数据【考试的时候作为样例下放】,也就是:

就可以发现一件事情——到了插入7的时候我们选择的是stc2而不是stc1,否则无解。【stc:stack】

而多数时候,在没有这种限制的情况下我们果断选择放到stc1里面去。

所以我们就从【无解】的角度切入。

当存在i<j<ka[k]<a[i]<a[j]的时候,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——

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值