学习C++从娃娃抓起!记录下蓝桥杯备考比赛学习过程中的题目,记录每一个瞬间。
附上汇总贴:蓝桥杯备考冲刺必刷题(C++) | 汇总-CSDN博客
【题目描述】
从小学开始,小明就是一个非常喜欢数学的孩子。他喜欢用数学的方式解决各种问题。在他的高中时期,他遇到了一个非常有趣的问题,那就是给定一个长度为$$n$$的整数数组$$nums
,判断是否存在四个不同的下标
, 判断是否存在四个不同的下标
,判断是否存在四个不同的下标a,b,c,d 使得
a
<
b
<
c
<
d
a\lt b\lt c\lt d
a<b<c<d, 并且
n
u
m
s
[
d
]
<
n
u
m
s
[
c
]
<
n
u
m
s
[
a
]
<
n
u
m
s
[
b
]
nums[d]<nums[c]<nums[a]<nums[b]
nums[d]<nums[c]<nums[a]<nums[b]。
小明非常喜欢这个问题,他决定用数学的方式来解决它。他首先想到了一个非常简单的方法,那就是暴力枚举。他用四个循环来枚举所有可能的下标组合,然后判断是否满足条件。但是这个方法非常耗时,当
n
n
n很大时,计算量会非常大。
所以请求你给出一个快速智慧的解决办法。
【输入】
输入仅两行,第一行包含一个整数
n
n
n,第二行包含
n
n
n个整数,其含义如上所述。
【输出】
输出仅一行,包含一个字符串,YES表示题目存在上面所描述的情况, 否则输出NO。
【输入样例】
4
3 4 2 1
【输出样例】
YES
【代码详解】
#include <bits/stdc++.h>
using namespace std;
int n, nums[500005], min_r[500005];
bool FoursNumberFind() {
stack<int > st; // 构造单调递减栈
int k=-1e9, INF=1e9;
for (int i=0; i<n; i++) { // 初始化min_r数组,记录最小值
min_r[i] = 1e9;
}
for (int i=n-2; i>=0; i--) { // 记录第i个数右边的最小值
min_r[i] = min(min_r[i+1], nums[i+1]);
}
for (int i=0; i<n; i++) {
if (nums[i]<k) { // 如果存在nums[i]<nums[a],即存在nums[c]<nums[a]<nums[b]的情况
if (nums[i]>min_r[i]) return true; // 如果c的右边有比nums[c]小的数,有则表示存在下标d,返回true
}
// cout << "11 " << endl;
while (!st.empty() && st.top()<nums[i]) { // 如果栈不为空,且栈顶小于nums[i]
// cout << "st.top num[i] " << st.top() << " " << nums[i] << endl;
// 需要找到满足小于nums[b]的最大k值,即nums[a]
k = max(k, st.top());
// cout << "k " << k << endl;
st.pop();
}
st.push(nums[i]); // 压入栈顶,即更新nums[b]
}
return false;
}
int main()
{
cin >> n;
for (int i=0; i<n; i++) {
cin >> nums[i];
}
if (FoursNumberFind()) {
cout << "YES" << endl;
} else {
cout << "NO" << endl;
}
return 0;
}
【运行结果】
4
3 4 2 1
YES