【BIT2021程设】19.填坑II

写在前面:

 

本系列博客仅作为本人十一假期过于无聊的产物,对小学期的程序设计作业进行一个总结式的回顾,如果将来有BIT的学弟学妹们在百度搜思路时翻到了这一条博客,也希望它能对你产生一点帮助(当然,依经验来看,每年的题目也会有些许的不同,所以不能保证每一题都覆盖到,还请见谅)。

不过本人由于学艺不精,代码定有许多不足之处,欢迎各位一同来探讨。

同时请未来浏览这条博客的学弟学妹们注意,对于我给出完整代码的这些题,仅作帮助大家理解思路所用(当然,因为懒,所以大部分题我都只给一个伪代码)。Anyway,请勿直接复制黏贴代码,小学期的作业也是要查重的,一旦被查到代码重复会严厉扣分,最好的方法是浏览一遍代码并且掌握相关的要领后自己手打一遍,同时也要做好总结和回顾的工作,这样才能高效地提升自己的代码水平。

加油!


Description

emmm,还是北湖深坑,不用惊喜,不用意外

我们继续用石头填!

北湖的地面依旧是一维的,每一块宽度都为1,高度是非负整数,用一个数组来表示。

还是提供不限量的 1\times2规格的石头。

但是这一次是DarkDown

来填坑,他有很强烈的强迫症,所有的石头只能水平摆放(宽为2,高为1)。

问这样是否可以将北湖填平。(所有地面到达同一高度即为填平)

Input

样例有多组输入至文件末尾;

每组用例占两行;

第一行输入1个整数 n(1\leq n\leq 2e5)表示北湖地面总宽度;

第二行输入n个数a_i(0\leq a_i\leq 1e9) ,用空格间隔,表示地面高度。

Output

若能填平则输出“YES”,否则输出“NO”。

测试用例 1以文本方式显示
  1. 5↵
  2. 2 1 1 2 5↵
  3. 3↵
  4. 4 5 3↵
  5. 3↵
  6. 1 2 3↵
以文本方式显示
  1. YES↵
  2. NO↵
  3. NO↵
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;  
}  

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里之码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值