写在前面:
本系列博客仅作为本人十一假期过于无聊的产物,对小学期的程序设计作业进行一个总结式的回顾,如果将来有BIT的学弟学妹们在百度搜思路时翻到了这一条博客,也希望它能对你产生一点帮助(当然,依经验来看,每年的题目也会有些许的不同,所以不能保证每一题都覆盖到,还请见谅)。
不过本人由于学艺不精,代码定有许多不足之处,欢迎各位一同来探讨。
同时请未来浏览这条博客的学弟学妹们注意,对于我给出完整代码的这些题,仅作帮助大家理解思路所用(当然,因为懒,所以大部分题我都只给一个伪代码)。Anyway,请勿直接复制黏贴代码,小学期的作业也是要查重的,一旦被查到代码重复会严厉扣分,最好的方法是浏览一遍代码并且掌握相关的要领后自己手打一遍,同时也要做好总结和回顾的工作,这样才能高效地提升自己的代码水平。
加油!
Description
emmm,还是北湖深坑,不用惊喜,不用意外
我们继续用石头填!
北湖的地面依旧是一维的,每一块宽度都为1,高度是非负整数,用一个数组来表示。
还是提供不限量的 规格的石头。
但是这一次是DarkDown
来填坑,他有很强烈的强迫症,所有的石头只能水平摆放(宽为2,高为1)。
问这样是否可以将北湖填平。(所有地面到达同一高度即为填平)
Input
样例有多组输入至文件末尾;
每组用例占两行;
第一行输入1个整数 表示北湖地面总宽度;
第二行输入n个数 ,用空格间隔,表示地面高度。
Output
若能填平则输出“YES”,否则输出“NO”。
测试用例 1 | 以文本方式显示
| 以文本方式显示
| 1秒 | 64M |
题意分析:
(无端吐槽:北湖的坑好惨,填了挖挖了填)
更不动了,先写作业,剩下的部分争取寒假前更完T^T
10.22回来更新,之前老师把提交的截止时间推迟了,我询问了一下邸老师他建议我先暂时停更一下,等截止之后再更新,免得因为代码抄袭有纠纷T^T 真的不是我故意鸽的。
其实这一题和上一题本质上没有啥区别,基本逻辑还是依靠栈,只是我们的策略要稍微变动那么一咩咩。在上一题中,我们可以把整个高度序列依靠竖直的石头转化成一个01序列,然而这题不行——因为不是所有情况都能够无限“垒高”。当且仅当相邻两块石头等高时,我们才可以做类似上一题的这个无限“垒高”的操作。
所以我们不难得出一个最基本的策略:不断将高度入栈,判断即将入栈的元素是否等于栈顶元素,如果等于栈顶元素那是我们最乐意看到的,这就意味着我们可以将他们垒到比当前高的任意高度;现在的问题就是,如果即将入栈的元素不等于栈顶元素怎么办?
分开来分析,首先是即将入栈的元素N小于栈顶元素T,这种情况我们能接受吗?答案是可以的,因为如果后续能够通过垒高将若干个位置的石头垒到T的高度,并且这个“若干”是奇数,那么T最终还是能假如到这个“若干个石头”组里面去,进而整个组可以垒到任意的高度,也是我们乐意见到的。
这么说可能比较抽象,我举个具体的例子:例如3223,这种情况下我们在压入第一个3之后,下一个元素2不等于3了,但是我们依然可以期待后面还会有2,这样就可以垒高两个2形成333——这个组和单一一个3是等价的,所以我们可以接受在单一3之后读入2,以期待这个2将来会被消掉。如果后面又读入一个3,那么这个剩下的3也被消掉,最好不过了。
那么如果即将入栈的元素N大于栈顶元素T,那么又会如何呢?我们举几个简单的例子,比如344,显然是我们不能接受的——因为最左边的3永远没有机会变高了;再比如3344,这个看似是我们能够接受的,但别忘了,我们在读入第二个3的时候就已经和前面的一个3形成配对消去了,所以这并不能算是入栈元素大于栈顶元素的情况。
总结一下,我们期待的仍然是一个之前讲过的结构——单调栈,只不过这个单调栈是动态变化的,比如说3355321,也满足我们所说的“单调栈”,因为“55”这个结构在过程中就会被消去,从而保留栈的单调性。
但是!还没完,我们还有一个结束条件没有研究。我们一定要求到最后栈完全为空吗?不尽然,例如题中给出的例子21125,按照我们的策略,最后栈中依然会剩下一个5,但是这个例子是可行的。然而我只要改动一下,改成21121,这个例子就不可行了,这里揭晓我们前面埋下的一个伏笔,我们说:“这就意味着我们可以将他们垒到‘比当前高’的任意高度”。我们为什么要强调“比当前高”呢?用前面这个例子就很容易明白,我们需要保证“消去”之后,最后如果栈不为空,栈内剩下的那个元素需要大于我们之前每一对“消去”的高度,以保证是让“他们”垒高来接近“我”,而不是让“他们”降低来满足“我”——毕竟,“我”只有孤零零一个人,并不能自己垒高自己。(莫名感伤T^T)
说到这整道题思路应该很清晰了,在伪代码环节我们再整理一下。
伪代码:
(按组循环:)
首先构造一个栈;
按序读入数据,每次读入以后:
如果栈空或栈顶元素大于新读入数据,直接入栈,进入下一次循环;
如果栈非空且栈顶元素小于新读入数据,直接输出NO,结束该组;
如果栈非空且栈顶元素等于新读入数据,弹出栈顶,同时更新当前最高的“消去”高度;
循环结束后,判断:
如果栈空,输出YES,结束该组;
如果栈非空,且剩余一个元素大于此前最高“消去”高度,输出YES,结束该组;
如果栈非空,且剩余一个元素小于此前最高“消去”高度,输出NO,结束该组;
贴代码:
#include <bits/stdc++.h>
#define pb push_back
#define pf push_front
#define __MAX 100010
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef stack<int> stk;
typedef unordered_map<int, int> umi;
typedef unordered_set<int> usi;
const int INF = 0x3f3f3f;
const double EPS = 1e-8;
const double PI = acos(-1);
int main(){
///ifstream infile("input.txt", ios::in);
///ofstream outfile("output.txt", ios::out);
int width;
bool stop = false; //更新结束条件
int last = 0; //用于记录最高的消去高度
int cache; //用于记录临时的栈顶(因为c++栈的pop无返回值,python就没有这个烦恼)
while(cin >> width){ //按组循环的奇技淫巧
stop = false;
last = 0; //定义在循环外,记得每轮都要重新初始化
stk s;
int tmp;
for(int i = 0; i < width; i++){
scanf("%d",&tmp);
if(stop)
continue;
if(s.empty()){
s.push(tmp);
}
else{
if(tmp == s.top()){
cache = s.top();
if(cache > last)
last = cache;
s.pop();
} else if(tmp < s.top()){
s.push(tmp);
} else{
stop = true;
}
}
}
if(stop or s.size() > 1 or (!s.empty() and s.top() < last and s.size() == 1))
cout << "NO" << endl;
else
cout << "YES" << endl;
}
return 0;
}