$[NOIp2008]$双栈排序 栈/二分图/贪心
\(Sol\)
先考虑单栈排序,怎么样的序列可以单栈排序呢?设\(a_i\)表示位置\(i\)是哪个数.\(\exist i<j<k\),都没有\(a_k<a_i<a_j\),这样的序列才可以单栈排序.
再来考虑双栈排序,如果把这个序列划分为两个子序列,这两个子序列分别可以单栈排序,那么这个序列就可以双栈排序了.
怎么划分子序列呢?预处理一个后缀最小值\(f_i=min_{j=i}^na_j\),若\(i<j\)且\(f_{j+1}<a_i<a_j\),那么说明\(i,j\)两个点是不能共存的.因为\(k\)在\(i\)后面,\(i\)只能入栈,但\(j\)也要入栈,而\(a_i<a_j\),不能使得较小的\(i\)先出栈.我们现在得到了若干对关系\((i,j)\)表示它们不能共存,现在我们要求把序列分成两部分满足任意一个部分内部没有这样的关系.这不就是二分图染色嘛\(QwQ\).染色完了之后就直接分别按照单栈的做就行.单栈做的时候还要注意字典序尽量小.
还有\(lx\)的优秀贪心做法,大概讲下:从第一个开始扫,一个数能进入\(stack1\)的条件是不能出现下面这种情况:在后面的数中有比该数和\(stack2\)的栈顶元素都大的元素,在这个大的元素的后面又有一个比该数小的数.简单理解下,因为后面有一个比该数小的数,所以该数入栈后不能在大元素要入栈前清出,大元素也不能进入\(stack2\),因为\(stack2\)的栈顶要等比它小的该数清出它才能清出,所以这种情况是不合法的.
\(Code\)
#include<bits/stdc++.h>
#define il inline
#define Ri register int
#define go(i,a,b) for(Ri i=a;i<=b;++i)
#define yes(i,a,b) for(Ri i=a;i>=b;--i)
#define e(i,u) for(Ri i=b[u];i;i=a[i].nt)
using namespace std;
il int read()
{
Ri x=0,y=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')y=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*y;
}
const int N=1001;
int n,p[N],mi[N],b[N],ct,s1[N],s2[N],t1,t2;bool col[N],vis[N];
struct nd{int v,nt;}a[N*2];
il void add(Ri u,Ri v){a[++ct]=(nd){v,b[u]};b[u]=ct;}
il bool dfs(Ri u,bool co)
{
col[u]=co;vis[u]=1;
e(i,u)
{
Ri v=a[i].v;
if(!vis[v])if(!dfs(v,1-co))return 0;;
if(vis[v] && col[v]!=1-co)return 0;
}
return 1;
}
il void ins1(Ri x){printf("a ");s1[++t1]=x;}
il void ins2(Ri x){printf("c ");s2[++t2]=x;}
il void pus1(){printf("b ");--t1;}
il void pus2(){printf("d ");--t2;}
int main()
{
n=read();
go(i,1,n)p[i]=read();
mi[n+1]=1e9;yes(i,n,1)mi[i]=min(mi[i+1],p[i]);
go(i,1,n)
go(j,i+1,n)
if(p[i]<p[j] && p[i]>mi[j+1])add(i,j),add(j,i);
go(i,1,n)
if(!vis[i])if(!dfs(i,0)){puts("0");return 0;};
go(i,1,n)
{
if(col[i]==0)
if(s1[t1]>p[i])ins1(p[i]);
else {while(t1 && s1[t1]<p[i])pus1();;ins1(p[i]);}
else
{
while(s1[t1]<mi[i+1])pus1();
if(s2[t2]>p[i])ins2(p[i]);
else {while(t2 && s2[t1]<p[i])pus2();;ins2(p[i]);}
}
}
while(t1 || t2)
{
if(!t2){pus1();continue;}
if(!t1){pus2();continue;}
if(s1[t1]<s2[t2])pus1();
else pus2();
}
return 0;
}
随机推荐
- HZOJ Blue
Blue: 贪心. 我们不妨给蛤定一个先后顺序,则贪心策略即从右至左每只蛤依次往最远的石子跳. 证明: 如果最右的蛤不往最远的石子跳,而是选择了一个较近的石子,那么必然会存在一个该蛤左边的蛤越过了它跳 ...
- @codeforces - 913F@ Strongly Connected Tournament
目录 @description@ @solution@ @accepted code@ @details@ @description@ n 个选手参加了一场竞赛,这场竞赛的规则如下: 1.一开始,所有 ...
- Android读取sd卡
public static String[] getStoragePaths() { List<String> pathsList = new ArrayList<String> ...
- 2014年最热门的国人开发开源软件TOP100
2014年最热门的国人开发开源软件TOP100 不知道从什么时候开始,很多一说起国产好像就非常愤慨,其实大可不必.做开源中国六年有余,这六年时间国内的开源蓬勃发展,从一开始的使用到贡献,到推出自己很多 ...
- Jmeter正则表达式提取多个值示例
首先了解一下常用正则表达式的语法 \d 数字 \w 数字或者字母 . 可以匹配任意字符 星号* 表示任意个字符 + ...
- functiils.lru_cache缩短递归时间
力扣上看到一道题: 假设你正在爬楼梯.需要 n 阶你才能到达楼顶. 每次你可以爬 1 或 2 个台阶.你有多少种不同的方法可以爬到楼顶呢? 注意:给定 n 是一个正整数. 使用普通递归解决,超出时间限 ...
- Python--day21--复习
序列化模块总结: jison格式化输出: Serialize obj to a JSON formatted str.(字符串表示的json对象) Skipkeys:默认值是False,如果dict的 ...
- 安装ssh-batch工具
关于sshbatch sshbatch是用perl写了非常方便操作管理集群的一个工具,项目的源码在GitHub托管. 关于sshbatch以及其详细的使用方法,春哥在GitHub上介绍的非常详细了,详 ...
- 【u238】暴力摩托
Time Limit: 1 second Memory Limit: 64 MB [问题描述] 晚会上大家在玩一款"暴力摩托"的游戏,它拥有非常逼真的画面和音响效果! 当然了,车子 ...
- 【React】 npm 常用的插件
npm install –save-dev package.json 安装环境 https://segmentfault.com/a/1190000008489881 全局 https:/ ...