luogu_1155: 双栈排序
洛谷1155:双栈排序
题意描述:
- 给定一个长度为\(n\)的序列\((n\leq 1000)\),两个初始为空的栈,问是否能借助以下四种操作将序列排为升序。
- \(1:\)如果序列不为空,将第一个元素压入栈\(S_1\)。记为操作\(a\)。
- \(2:\)如果栈\(S_1\)不为空,将\(S_1\)栈顶元素弹出至输出序列。记为操作\(d\)。
- \(3:\)输入序列不为空,将第一个元素压入栈\(S_2\)。记为操作\(c\)。
- \(4:\) 如果栈\(S_2\)不为空,将\(S_2\)栈顶元素弹出至输出序列。记为操作\(d\)。
输出描述:
- 输出字典序最小的操作序列,如果不满足双栈排序性质,输出\(0\)。
思路:
- 写了半天单调栈+贪心+模拟被提醒是二分图。
- 写一篇题解纪念我逝去的三个小时。
- 首先有这样一个性质。
- 如果存在这种情况\(i<j<k\)且\(a(k)<a(i)<a(j)\),那么\(a(i),a(j)\)不能处于同一个栈内,这是一个充分必要条件。
- 证明:
- 必要性:如果有\(i<j<k\)且\(a(k)<a(i)<a(j)\),则因为\(a(i)\)和\(a(j)\)后面都存在一个更小的数\(a(k)\),因此\(a(i),a(j)\)都不能从栈中被弹出。所以从栈底到栈顶的元素就不是一个单调递减的降序了,那么弹出的时候就会出现逆序对,因此\(a(i),a(j)\)不能分配到同一个栈中。
- 充分性:如果\(a(i),a(j)\)不满足上述条件,则在操作过程中一定不会出现矛盾。
- 所有大于\(a(j)\)的元素,都一定在栈中;
- 所有小于\(a(j)\)的元素,比如说\(a(i)<a(j)\),则由于后面不存在\(a(k)<a(i)\),因此\(a(i)\)已经出栈。
- 所以将\(a(j)\)压入栈中,从栈底到栈顶依然可以保持降序,因此整个过程都是可以顺利进行的。
- 有了上述性质后,我们只需要将所有满足条件的点分到两个栈中,这一步可以转化为图论问题。
- 枚举所有点对,如果\(i,j\)满足能在一个栈条件,则在\(i,j\)加边。
- 当然枚举所有点对同时考虑上述条件,会发生一件很糟糕的事情。
- 我枚举点对需要\(O(n^2)\)的时间复杂度,同时我需要向后扫描找到有没有更小的数字则需要\(O(n)\)的时间复杂度,总共就会要\(O(n^3)\),无法通过。
- 想办法优化这一步,我们可以预处理\(f(i)=min(a_j)\)。\(j\)从\(i\)到\(n\)。
- 这样就可以\(O(n^2)\)枚举点对,判断是否有\(i,j\)满足条件,也就是\(f_{j+1}<a_i<a_j\)。
- 然后判断是否为二分图,从而判断是否能满足双栈排序的性质,可以用染色法。
- 又因为字典序要求最小,所以优先将点分配到\(S_1\)中。
- 之后模拟双栈排序,得出答案。
复杂度分析:
- 建图枚举所有点对\(O(n^2)\)。
- 染色法判定二分图\(O(n+m)\)。
- 模拟栈排序\(O(n)\)。
- 总时间复杂度为\(O(n^2)\),可以通过。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e3 + 10;
const int INF = 0x3f3f3f3f;
int n, a[maxn], f[maxn];
int head[maxn], ver[maxn<<5], nex[maxn<<5], tot;
inline void add_edge(int x, int y){
ver[++tot] = y; nex[tot] = head[x]; head[x] = tot;
}
int color[maxn];
bool dfs(int x, int c)
{
color[x] = c;
for(int i = head[x]; i; i = nex[i])
{
int y = ver[i];
if(!color[y])
{
if(!dfs(y, 3 - c)) return false;
}
else if(color[y] == c) return false;
}
return true;
}
int main()
{
scanf("%d", &n); f[n+1] = INF;
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
for(int i = n; i >= 1; i--) f[i] = min(f[i+1], a[i]);
for(int i = 1; i < n; i++)
for(int j = i + 1; j < n; j++)
if(a[i] > f[j+1] && a[i] < a[j])
add_edge(i, j), add_edge(j, i);
bool flag = true;
for(int i = 1; i <= n; i++)
{
if(!color[i])
{
if(!dfs(i, 1))
{
flag = false;
break;
}
}
}
if(flag == false) puts("0");
else
{
stack<int> stk1, stk2;
int cnt = 1;
for(int i = 1; i <= n; i++)
{
if(color[i] == 1)
{
stk1.push(a[i]);
printf("a ");
}
else{
stk2.push(a[i]);
printf("c ");
}
while((!stk1.empty() && stk1.top() == cnt) || (!stk2.empty() && stk2.top() == cnt))
{
if(!stk1.empty() && stk1.top() == cnt)
{
stk1.pop();
cnt++;
printf("b ");
}
else
{
stk2.pop();
cnt++;
printf("d ");
}
}
}
}
return 0;
}
luogu_1155: 双栈排序的更多相关文章
- NOIP2008双栈排序[二分图染色|栈|DP]
题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操作b 如果栈S1 ...
- noip2008 双栈排序
题目描述 Description \(Tom\)最近在研究一个有趣的排序问题.如图所示,通过\(2\)个栈\(S_1\)和\(S_2\),\(Tom\)希望借助以下\(4\)种操作实现将输入序列升序排 ...
- BZOJ 2080: [Poi2010]Railway 双栈排序
2080: [Poi2010]Railway Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 140 Solved: 35[Submit][Statu ...
- 双栈排序(codevs 1170)
题目描述 Description Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈 ...
- #include <NOIP2008 Junior> 双栈排序 ——using namespace wxl;
题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操作b 如果栈S1 ...
- [NOIP2008] 提高组 洛谷P1155 双栈排序
题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操作b 如果栈S1 ...
- 【NOIP2008】双栈排序
感觉看了题解还是挺简单的,不知道当年chty同学为什么被卡了呢么久--所以说我还是看题解了 原题: Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将 ...
- 双栈排序(codevs 1170)题解
[问题描述] Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操作b 如果栈 ...
- Noip2008双栈排序
[问题描述] 用两个栈使一个1...n的排列变得有序.一共有四个操作: A.stack1.push() 读入一个放入栈一 B.stack1.pop() 弹出栈一放入输出序列 C.stack2.push ...
随机推荐
- gevent介绍(转)
原文:https://www.liaoxuefeng.com/wiki/897692888725344/966405998508320 Python通过yield提供了对协程的基本支持,但是不完全.而 ...
- Java学习:数据类型转换注意事项
数据类型的转换 当数据类型不一样时,将会发生数据类型转换. 自动类型转换(隐式) 1.特点 :代码不需要进行特殊处理,自动完成. 2.规则 :数据范围从小到大. //左边是long类型,右边是默认的i ...
- jquery 获取后台实时数据
第一步.提醒后台处理数据1.$.ajax({}) 提交数据,2.后台返回状态3.后台开始处理数据,并每秒记录状态到 data.json 文件4.前台每秒请求 data.json 文件,直到处理完成 第 ...
- ASP.NET Core 配置文件
在ASP.NET Core 中,应用程序配置数据可以使用JSON, XML 和 INI格式 和内置环境变量,命令行参数或内存中的集合. 1.如何获取和设置配置 ASP.NET Core配置系统针对以前 ...
- 彻底理解javascript中的this指针
http://javascriptissexy.com/understand-javascripts-this-with-clarity-and-master-it/ https://www.benn ...
- IntelliJ Cannot find declaration to goto----解决方案
系统中已经有了该类库,还是找不到类提示 close the project in intellij. close intellij. go to the project folder and dele ...
- ASP.NET Core 2.2在中间件内使用有作用域的服务
服务生存期 为每个注册的服务选择适当的生存期.可以使用以下生存期配置ASP.NET Core服务: 暂时 暂时生存期服务 (AddTransient) 是每次从服务容器进行请求时创建的. 这种生存期适 ...
- 请实现一个js脚本,要求做到将数字转化为千分位表示如:1234567转化为1,234,567
//法一 function parseNum(num){ var list = new String(num).split('').reverse(); for(var i = 0; i < l ...
- ES6 对象解构赋值(浅拷贝 VS 深拷贝)
对象的扩展运算符(...)用于取出参数对象的所有可遍历属性,拷贝到当前对象之中. 拷贝对象 let aa = { age: 18, name: 'aaa' } let bb = {...aa}; co ...
- Kubernetes学习之基础概念
本文章目录 kubernetes特性 kubernetes集群架构与组件 一.kubernetes集群架构 二.集群组件 三.ubernetes集群术语 深入理解Pod对象 一.Pod容器分类 基础容 ...