NOIP 2008 Senior 4
来源:互联网 发布:昆明暴恐 中国公知 编辑:程序博客网 时间:2024/06/07 11:54
传送门
这道题可以说难点有两个。一是证明在何种条件下两个数不能进入同一个栈,二是如何贪心使字典序最小并且能够正确写出代码(样例太坑了,只用了一个栈)。
对于第一个问题,我们发现,如果存在 大的 在 小的 的后面,并且有一个 更小的 在后面,那么 大的 就不能和 小的 在同一个栈中,否则就可以。因为我们要先输出那个 更小的,就势必要先把 大的 和 小的 入栈,且在输出 更小的 之前这两个都没有出栈。所以 大的 和 小的 一定不能在同一个栈中,否则一定会先输出大的,后输出小的。
以上是一个充分性证明,但还没有必要性证明,即我们还没有证明“否则就可以”。这里我就给个写得很厉害的链接,自己去看看吧。。。考场上如果你能找到充分性证明的话,可以算是成功了一大半了。
传送门
然后,我们就可以把不能在同一个栈的元素跑一次二分图染色。如果跑出来的结果不是二分图,那么问题无解。否则问题就有解。
接下来,我们就要考虑生成字典序最小的操作序列了。首先,我们肯定得先考虑用第一个栈。但是怎么判断呢?由于我们染色时是优先染的黑色的(假设分为黑色和白色),那么我们就让黑色放到栈1,白色放到栈2。入栈的前提条件就多了一个颜色相互匹配。
但有可能着急地把一个元素放进栈中,导致一个该出栈的元素被压在了下面。所以我们要先检查是否该出栈了,再考虑入栈的事情。
最后还有一个坑。如果此时栈1可以出栈,而新元素可以进栈2,那么我们要先让栈1出栈。
参考代码
#include <cstdio>#include <cstdlib>#include <cmath>#include <cstring>#include <iostream>#include <algorithm>#include <vector>#include <string>#include <stack>#include <queue>#include <deque>#include <map>#include <set>#include <bitset>using std::cin;using std::cout;using std::endl;typedef int INT;inline INT readIn(){ INT a = 0; bool minus = false; char ch = getchar(); while (!(ch == '-' || ch >= '0' && ch <= '9')) ch = getchar(); if (ch == '-') { minus = true; ch = getchar(); } while (ch >= '0' && ch <= '9') { a *= 10; a += ch; a -= '0'; ch = getchar(); } if (minus) a = -a; return a;}const INT INF = (~(INT(1) << (sizeof(INT) * 8 - 1)));const INT maxn = 1005;INT n;INT a[maxn];std::vector<std::vector<INT> > edges;INT vis[maxn];bool dfs(INT node, INT color){ vis[node] = color; for(int i = 0; i < edges[node].size(); i++) { INT to = edges[node][i]; if(vis[to] == color) return false; else if(vis[to] == !color) continue; else if(!dfs(to, !color)) return false; } return true;}void run(){ n = readIn(); for(int i = 1; i <= n; i++) { a[i] = readIn(); } edges.resize(n + 1); INT minVal = INF; for(int i = n; i >= 1; i--) { for(int j = 1; j < i; j++) { if(a[j] < a[i] && minVal < a[j]) { edges[j].push_back(i); edges[i].push_back(j); } } minVal = std::min(minVal, a[i]); } bool bOk = true; memset(vis, -1, sizeof(vis)); for(int i = 1; i <= n; i++) { if(!~vis[i]) { bOk = dfs(i, 0); if(!bOk) break; } } if(!bOk) { cout << 0 << endl; return; } INT input = 1; INT output = 1; std::stack<INT> s1, s2; s1.push(a[1]); input++; cout << "a"; while(output <= n) { if(!s1.empty() && s1.top() == output) { s1.pop(); output++; cout << " b"; } else if(!vis[input] && (s1.empty() || s1.top() > a[input])) { s1.push(a[input]); input++; cout << " a"; } else if(!s2.empty() && s2.top() == output) { s2.pop(); output++; cout << " d"; } else if(vis[input] && (s2.empty() || s2.top() > a[input])) { s2.push(a[input]); input++; cout << " c"; } }}int main(){ run(); return 0;}
阅读全文
0 0
- NOIP 2008 Senior 4
- NOIP 2009 Senior 4
- NOIP 2011 Senior 4
- NOIP 2015 Senior 4
- NOIP 2013 Senior 4
- NOIP 2016 Senior 4
- NOIP 2007 Senior 4
- NOIP 2009 Senior 1
- NOIP 2009 Senior 3
- NOIP 2011 Senior 2
- NOIP 2011 Senior 3
- NOIP 2011 Senior 5
- NOIP 2011 Senior 6
- NOIP 2012 Senior 2
- NOIP 2012 Senior 5
- NOIP 2012 Senior 3
- NOIP 2015 Senior 2
- NOIP 2015 Senior 3
- [Java]stop()不能用,如何停止线程?
- 最后冲刺—信息系统开发与管理
- okhttp上传文件
- Python chapter 5 learning notes
- Docker学习笔记
- NOIP 2008 Senior 4
- 注册登录展示数据
- Python-Day04-装饰器(2)
- C++中String类型的逆序
- Python chapter 6 learning notes
- 1.GDI+ 常用方法详解
- 直接排序算法
- 第 0004 题: 任一个英文的纯文本文件,统计其中的单词出现的个数
- Python chapter 7 learning notes