洛谷 1155 (NOIp2008)双栈排序——仔细分析不合法的条件
题目:https://www.luogu.org/problemnew/show/P1155
这道题教会我们要多思考。
好好分析过后发现同一个栈里不能有升序。就用它写了一个30分。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=;
int n,stack[][N],top[],nw,tot,ps[N];
char ch[N<<];
bool flag;
int main()
{
scanf("%d",&n);int x;nw=;
stack[][]=stack[][]=n+;
for(int i=;i<=n;i++)
{
scanf("%d",&x);
if(stack[][top[]]>x){
stack[][++top[]]=x;
ch[++tot]='a';ps[x]=;
}
else if(stack[][top[]]>x){
stack[][++top[]]=x;
ch[++tot]='c';ps[x]=;
}
else {
flag=;break;
}
while(ps[nw])
{
if(ps[nw]==){
top[]--;ch[++tot]='b';
}
else{
top[]--;ch[++tot]='d';
}
nw++;
}
}
if(flag)printf("");
else for(int i=;i<=tot;i++)printf("%c ",ch[i]);
return ;
}
然后发现只有30分。想想自己想得太简单了。于是写了个深搜30分。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=;
int n,stack[][N],top[],tot,ps[N],a[N];
char ch[N<<];
bool flag;
void rd(int x,int k)
{
stack[k][++top[k]]=x;ch[++tot]=(k?'c':'a');ps[x]=k+;
// printf("stack%d=%d(top[k]=%d)\n",k,stack[k][top[k]],top[k]);
}
void clr(int x,int k)
{
top[k]--;tot--;ps[x]=;
}
void cd(int &nw)
{
// printf("cd!\n");
while(ps[nw])
{
if(ps[nw]==){
top[]--;ch[++tot]='b';
}
else{
top[]--;ch[++tot]='d';
}
nw++;
}
}
void dfs(int cr,int nw)
{
if(cr>n)return;
int x=a[cr],tnw=nw;bool cflag=;
int tsk[][N];memcpy(tsk,stack,sizeof stack);
if(stack[][top[]]>x&&stack[][top[]]<x)
{
rd(x,);
if(ps[nw])cflag=,cd(nw);
// printf("cr=%d 0\n",cr);
dfs(cr+,nw);
if(flag){
if(cflag){
tot-=nw-tnw;top[]+=nw-tnw;nw=tnw;
memcpy(stack,tsk,sizeof tsk);
}
clr(x,);
// printf("ret cr=%d flag=1\n",cr);
}
}
else if(stack[][top[]]>x&&stack[][top[]]<x)
{
rd(x,);
if(ps[nw])cflag=,cd(nw);
// printf("cr=%d 1\n",cr);
dfs(cr+,nw);
if(flag){
if(cflag){
tot-=nw-tnw;top[]+=nw-tnw;nw=tnw;
memcpy(stack,tsk,sizeof tsk);
}
clr(x,);
// printf("ret cr=%d flag=1\n",cr);
}
}
else if(stack[][top[]]<x&&stack[][top[]]<x)
{
// printf("cr=%d flag=1!\n",cr);
flag=;return;
}
else{
// printf("stack0=%d stack1=%d(top0=%d top1=%d)\n",stack[0][top[0]],stack[1][top[1]],top[0],top[1]);
rd(x,);
if(ps[nw])cflag=,cd(nw);
// printf("cr=%d try0\n",cr);
dfs(cr+,nw);
if(flag){
if(cflag){
tot-=nw-tnw;top[]+=nw-tnw;nw=tnw;
memcpy(stack,tsk,sizeof tsk);
}
clr(x,);
// printf("cr=%d failtry0 try1\n",cr);
flag=;cflag=;rd(x,);
if(ps[nw])cflag=,cd(nw);
dfs(cr+,nw);
if(flag){
if(cflag){
tot-=nw-tnw;top[]+=nw-tnw;nw=tnw;
memcpy(stack,tsk,sizeof tsk);
}
clr(x,);
// printf("cr=%d failtry1\n",cr);
}
}
}
}
int main()
{
scanf("%d",&n);int x;
stack[][]=stack[][]=n+;
for(int i=;i<=n;i++)scanf("%d",&a[i]);
dfs(,);
if(flag)printf("");
else for(int i=;i<=tot;i++)printf("%c ",ch[i]);
return ;
}
然后发现只有30分。那就剪剪枝吧。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=;
int n,stack[][N],top[],tot,ps[N],a[N];
char ch[N<<];
bool flag;
void rd(int x,int k)
{
stack[k][++top[k]]=x;ch[++tot]=(k?'c':'a');ps[x]=k+;
// printf("stack%d=%d(top[k]=%d)\n",k,stack[k][top[k]],top[k]);
}
void clr(int x,int k)
{
top[k]--;tot--;ps[x]=;
}
void cd(int &nw)
{
// printf("cd!\n");
while(ps[nw])
{
if(ps[nw]==){
top[]--;ch[++tot]='b';
}
else{
top[]--;ch[++tot]='d';
}
nw++;
}
}
bool check(int cr,int x)
{
int i;
for(i=cr+;i<=n;i++)if(a[i]>a[cr]&&a[i]>x)break;
for(int j=i+;j<=n;j++)if(a[j]<a[cr])return ;//导致在j之前cr不能弹出
return ;
}
void dfs(int cr,int nw)
{
if(cr>n)return;
int x=a[cr],tnw=nw;bool cflag=;
int tsk[][N];memcpy(tsk,stack,sizeof stack);
if(stack[][top[]]>x&&stack[][top[]]<x)
{
rd(x,);
if(ps[nw])cflag=,cd(nw);
// printf("cr=%d 0\n",cr);
dfs(cr+,nw);
if(flag){
if(cflag){
tot-=nw-tnw;top[]+=nw-tnw;nw=tnw;
memcpy(stack,tsk,sizeof tsk);cflag=;
}
clr(x,);
// printf("ret cr=%d flag=1\n",cr);
}
}
else if(stack[][top[]]>x&&stack[][top[]]<x)
{
rd(x,);
if(ps[nw])cflag=,cd(nw);
// printf("cr=%d 1\n",cr);
dfs(cr+,nw);
if(flag){
if(cflag){
tot-=nw-tnw;top[]+=nw-tnw;nw=tnw;
memcpy(stack,tsk,sizeof tsk);cflag=;
}
clr(x,);
// printf("ret cr=%d flag=1\n",cr);
}
}
else if(stack[][top[]]<x&&stack[][top[]]<x)
{
// printf("cr=%d flag=1!\n",cr);
flag=;return;
}
else{
// printf("stack0=%d stack1=%d(top0=%d top1=%d)\n",stack[0][top[0]],stack[1][top[1]],top[0],top[1]);
if(check(cr,stack[][top[]]))
{
rd(x,);
if(ps[nw])cflag=,cd(nw);
// printf("cr=%d try0\n",cr);
dfs(cr+,nw);
if(flag){
if(cflag){
tot-=nw-tnw;top[]+=nw-tnw;nw=tnw;
memcpy(stack,tsk,sizeof tsk);cflag=;
}
clr(x,);
}
}
if(flag&&check(cr,stack[][top[]]))
{
flag=;rd(x,);
if(ps[nw])cflag=,cd(nw);
dfs(cr+,nw);
if(flag){
if(cflag){
tot-=nw-tnw;top[]+=nw-tnw;nw=tnw;
memcpy(stack,tsk,sizeof tsk);cflag=;
}
clr(x,);
// printf("cr=%d failtry1\n",cr);
}
}
if(flag||(!check(cr,stack[][top[]])&&!check(cr,stack[][top[]])))flag=;
}
}
int main()
{
scanf("%d",&n);int x;
stack[][]=stack[][]=n+;
for(int i=;i<=n;i++)scanf("%d",&a[i]);
dfs(,);
if(flag)printf("");
else for(int i=;i<=tot;i++)printf("%c ",ch[i]);
return ;
}
然后发现只有30分。而且T1WA6。
在写搜索之前看了看TJ,体现在最后那个check里。就是如果a[1],a[2],a[3]满足a[2]>a[1],a[3]<a[1]的话,在a[3]来之前a[1]不能出栈,就被堵在了a[2]后面,从而GG。
但是这竟然就是唯一的GG条件!需要仔细思考。
这个性质和自己开始分析出来的浅显性质的不同之处:
1.自己的那个只有在过程中才能判断,因为一开始有升序,也可能前面小的先出栈,后面大的再进来。
而正解的想法是把这个不确定因素也分析掉,得出如果在这个大的后面又有一个比最前面的更小的,就真的不行了。
这样就能不在过程中判断而可以预先判断了。
2.自己对“两个栈”认识不足。明明可以把它看成一个主栈和一个辅助栈,用上一条判断出不能往主栈放就放在辅助栈里,可自己……
没错,正解这样想的话就可以只关注元素能不能放在同一个栈中。然后想到只有两个栈,于是二分图染色就有了。
因为判掉了无解,所以最后的模拟可以开放又随便。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=;
int n,a[N],head[N],xnt,col[N],ps[N],now,f[N];
bool flag;
struct Edge{
int next,to;
Edge(int n=,int t=):next(n),to(t) {}
}edge[N*N];
void add(int x,int y)
{
edge[++xnt]=Edge(head[x],y);head[x]=xnt;
edge[++xnt]=Edge(head[y],x);head[y]=xnt;
}
void init()
{
f[n]=n+;
for(int i=n-;i;i--)
{
f[i]=min(f[i+],a[i+]);
for(int j=i+;j<=n;j++)
if(a[j]>a[i]&&f[j]<a[i])add(i,j);
}
}
void dfs(int cr)
{
for(int i=head[cr],v;i;i=edge[i].next)
{
if(col[v=edge[i].to]==col[cr])
{flag=;return;}
else if(!col[v])col[v]=(col[cr]^),dfs(v);
if(flag)return;
}
}
int main()
{
scanf("%d",&n);
for(int i=;i<=n;i++)scanf("%d",&a[i]);
init();
for(int i=;i<=n;i++) if(!col[i])
{
col[i]=;dfs(i);if(flag)break;
}
if(flag){
printf("");return ;
}
now=;
for(int i=;i<=n;i++)
{
ps[a[i]]=col[i];
if(col[i]==)printf("a ");
else printf("c ");
while(ps[now]){
if(ps[now++]==)printf("b ");
else printf("d ");
}
}
return ;
}
从代码的col和ps可以看出二分图染色和最后的模拟有一定程度的重复。其实可以大胆地直接模拟就行了。
(此方法源自洛谷用户cmd2001。在洛谷题解的第2页可以看到。)
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=;
int n,r[N],ct,now,a[N],ta,b[N],tb,tot;
char ch[N<<];
bool flag;
bool check(int cr)
{
int i;
for(i=cr+;i<=n;i++)if(r[i]>r[cr]&&r[i]>b[tb])break;
for(int j=i+;j<=n;j++)if(r[j]<r[cr])return ;
return ;
}
int main()
{
scanf("%d",&n);int lm=(n<<);now=;ct=;
for(int i=;i<=n;i++)scanf("%d",&r[i]);
a[]=b[]=n+;
for(int i=;i<=lm;i++)
{
if(a[ta]==now)
{
ch[++tot]='b';ta--;now++;
continue;
}
if(b[tb]==now)
{
ch[++tot]='d';tb--;now++;
continue;
}
if(ct<=n&&r[ct]<a[ta]&&check(ct))
{
a[++ta]=r[ct++];ch[++tot]='a';
continue;
}
if(ct<=n&&r[ct]<b[tb])
{
b[++tb]=r[ct++];ch[++tot]='c';
continue;
}
flag=;break;
}
if(flag)printf("");
else for(int i=;i<=lm;i++)printf("%c ",ch[i]);
return ;
}
这道题教会我们要好好分析性质。别只分析出一个浅显的了!
洛谷 1155 (NOIp2008)双栈排序——仔细分析不合法的条件的更多相关文章
- Luogu1155 NOIP2008 双栈排序 【二分图染色】【模拟】
Luogu1155 NOIP2008 双栈排序 题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过 2个栈 S1 和 S2 ,Tom希望借助以下 44 种操作实现将输入序列升序排序. 操作 ...
- NOIP2008双栈排序[二分图染色|栈|DP]
题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操作b 如果栈S1 ...
- noip2008 双栈排序
题目描述 Description \(Tom\)最近在研究一个有趣的排序问题.如图所示,通过\(2\)个栈\(S_1\)和\(S_2\),\(Tom\)希望借助以下\(4\)种操作实现将输入序列升序排 ...
- Noip2008双栈排序
[问题描述] 用两个栈使一个1...n的排列变得有序.一共有四个操作: A.stack1.push() 读入一个放入栈一 B.stack1.pop() 弹出栈一放入输出序列 C.stack2.push ...
- NOIP2008双栈排序(贪心)
题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操作b 如果栈S1 ...
- [题解] [NOIP2008] 双栈排序——关系的冲突至图论解法
Problem 题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操 ...
- [NOIP2008]双栈排序 【二分图 + 模拟】
题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操作b 如果栈S1 ...
- [luogu1155 NOIP2008] 双栈排序 (二分图染色)
传送门 Description Input 第一行是一个整数 n . 第二行有 n 个用空格隔开的正整数,构成一个 1−n 的排列. Output 共一行,如果输入的排列不是"可双栈排序排列 ...
- $[NOIp2008]$双栈排序 栈/二分图/贪心
\(Sol\) 先考虑单栈排序,怎么样的序列可以单栈排序呢?设\(a_i\)表示位置\(i\)是哪个数.\(\exist i<j<k\),都没有\(a_k<a_i<a_j\), ...
随机推荐
- Spring Boot 快速入门(IDEA)
从字面理解,Boot是引导的意思,因此SpringBoot帮助开发者快速搭建Spring框架:SpringBoot帮助开发者快速启动一个Web容器:SpringBoot继承了原有Spring框架的优秀 ...
- HTTP Message Handlers in ASP.NET Web API
https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/http-message-handlers A message ha ...
- [POI2009]Lyz
Description 初始时滑冰俱乐部有1到n号的溜冰鞋各k双.已知x号脚的人可以穿x到x+d的溜冰鞋. 有m次操作,每次包含两个数ri,xi代表来了xi个ri号脚的人.xi为负,则代表走了这么多人 ...
- contos LAMP环境搭建
LINUX搭建LAMP笔记 .YUM:Yum(全称为 Yellow dog Updater, Modified)是一个在Fedora和RedHat以及CentOS中的Shell前端软件包管理器.基于R ...
- mac 安装python3
Python有两个版本,一个是2.x版,一个是3.x版,这两个版本是不兼容的. 现在 Mac 上默认安装的 python 版本为 2.7 版本,若 安装 新版本需要 通过 该地址进行下载: http ...
- python 获取探针页面,自动查询公司出口
在一些渗透当中,我们需要批量探针出口来达到我们的目的. 所以就有了这个丑陋简洁的小脚本. #!/usr/bin/env python #-*- coding:utf- -*- import sys i ...
- Android -- 创建XML文件对象及其序列化, pull解析XML文件
1. 创建XML文件对象及其序列化 示例代码:(模拟以xml格式备份短信到SD卡) SmsInfo.java, bean对象 /** * 短信的业务bean * @author Administrat ...
- Android -- 工程架构,电话拨号器, 点击事件的4中写法
(该系列整理自张泽华android视频教程) 1. android工程 各个文件夹的作用 src/ java原代码存放目录 gen/ 自动生成目录 gen 目录中存放所有由Android开发工具自动 ...
- Linux集群的NTP服务器时间同步
我们搭建集群环境的时候,时间必须是要统一的,才能保证集群数据的一致性. 一般操作是直接使用NTP,跟默认的时间服务器同步,但是最好还是让所有节点跟集群中的某台作为时间服务器的节点同步. 步骤:(节点有 ...
- spring3: schema的aop与Aspectj的aop的区别
schema的aop如下: 接口: package chapter6.service; public interface IHelloAroundService { public void sayAr ...