速通ACM省铜第十八天 赋源码(Neo‘s Escape)
目录
Neo's Escape
题意分析
逻辑梳理
代码实现
AC方法一
AC方法二
结语:
我们今天来讲一道CF评级为1400的题,昨天断了1天是因为这题目我不知道为什么WA 了,还WA在很后面的样例里,所以思考了一段时间,那么接下来,就进入今天的题目讲解啦——————————————>
Neo's Escape
我们先来看题目
题意分析
题目链接在这里Problem - C - Codeforces
不想跳转的可看下图
题目虽然很长,但其实题意很简单,就是给你一个排成一排的按钮,然后,最后要根据从大到小的顺序来按亮按钮,每个按钮按下后就不会弹起了
然后玩家可以选择俩种方式
一.在一个位置上放置一个机器人,并按下当前位置的按钮
二.将现有的机器人向左或向右移动一格,若按钮没按下去就按下去
然后要按照从大到小的顺序按亮所有按钮,问你最少需要几个机器人
题意就这么简单,接下来我们进入逻辑梳理环节
逻辑梳理
这题逻辑其实很简单的,就是我们可以先把所有的数据看成一条折线,如图
像这个图,我们就可以分为三部分,具体分割点在哪,就是在每次的线段谷底,这个看图其实就很明显了,每个制高点都放个机器,负责把每个部分都按完,非常简单哇
只是需要注意一下,一开始需要的机器人数量要设置为1,因为,分割线的存在说明要多一个机器人,但是就算没有分割线,也是需要一个机器人来按按钮的
那么接下来,我们进入代码实现环节
代码实现
这个在代码实现环节,我一开始是使用差分来做这道题的,来判断每个的折点,我也是因为其中一个小细节的错误让我一直找不到错在哪
我们先来看这个代码的实现,这是错误代码
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <math.h>
#include <queue>
#include <vector>
using namespace std;int a[200010];
int cha[200010];void solve()
{int n;cin >> n;long long ans = 1;for (int i = 1; i <= n; i++){cin >> a[i];cha[i] = a[i] - a[i - 1];if (cha[i] > 0 && cha[i - 1] < 0)ans++;}cout << ans << endl;
}int main()
{int t;cin >> t;while (t--){solve();}return 0;
}
这个代码粗粗看是没有问题的,但细细考虑,会发现他找谷底的时候会出问题,什么情况下会出现问题呢,那就是在谷底是多个相同数的时候,谷底的判断就会出问题,因为那是cha[i-1]就是等于0了,而不是小于0,进不去分支判断语句了
这时候怎么修改呢,可以在这个代码的基础上进行修改,把那种连续的重复元素只留一个
这是一种方法,但是在思考这个问题的时候我发现了更简单的俩种方法
AC方法一
只需要先去掉重复元素后,直接找有多少个峰顶就可以了,这个怎么得来的,就是在逻辑梳理里所讲的,每次都找那部分最大的地方放机器人得出来的,然后往里细细推,就能得到有多少个峰顶就需要多少个机器人的结论,接下来,我们来看代码
那至于怎么找峰顶,很简单,就俩边的数比中间小就好了
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <math.h>
#include <queue>
#include <vector>
using namespace std;int a[200010];void solve()
{memset(a, 0, sizeof(a));int n;cin >> n;long long ans = 0;long long j = 1;int wei = 1;for (int i = 1; i <= n; i++){cin >> j;if (a[wei - 1] != j)a[wei++] = j;}for (int i = 1; i < wei; i++)if (a[i] > a[i - 1] && a[i] > a[i + 1])ans++;cout << ans << endl;
}int main()
{int t;cin >> t;while (t--){solve();}return 0;
}
AC方法二
第二种方法就是一开始的错误衍生过来的,因为要找的是谷底,那么只需要去掉重复元素后,通过比较前后俩位与中间的大小关系就好了,然后最后结果就是在这个基础上再加一,因为错误代码就是这个思路,只是找谷底的代码上细节处理有点问题,这个就完美处理了细节错误,也不需要开第二个数组
那么接下来,我们来看可以AC的第二种方式的码
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <math.h>
#include <queue>
#include <vector>
using namespace std;long long a[200010];void solve()
{int n;cin >> n;long long ans = 1;long long j = 1;long long wei = 1;for (int i = 1; i <= n; i++){cin >> j;if (a[wei - 1] != j)a[wei++] = j;}for (int i = 2; i < wei-1; i++){if (a[i] < a[i - 1] && a[i] < a[i + 1])ans++;}cout << ans << endl;
}int main()
{int t;cin >> t;while (t--){solve();}return 0;
}
那么,这题就讲解完啦
结语:
今日算法讲解到此结束啦,希望对你们有所帮助,谢谢观看,如果觉得不错可以分享给朋友哟。当然也可以关注一下,有什么看不懂的可以评论问哦