F. Find my Family
https://nanti.jisuanke.com/t/44322
题意:
n
n
n个数的序列,判断是否存在三个数
h
[
i
]
、
h
[
j
]
、
h
[
k
]
,
i
<
j
<
k
,
h
[
j
]
<
h
[
i
]
<
h
[
k
]
h[i]、h[j]、h[k],i<j<k,h[j]<h[i]<h[k]
h[i]、h[j]、h[k],i<j<k,h[j]<h[i]<h[k]。
思路:
预处理右边的最大值,
m
a
x
_
h
[
i
]
max\_h[i]
max_h[i]表示
[
i
,
n
]
[i,n]
[i,n]的最大值。
然后从左往右对每个点判断左边是否符合条件,可以用set
存
i
i
i 之前的数,然后二分(upper_bound()
)找大于
h
[
i
]
h[i]
h[i] 的最小的数。
Code:
/*
* @Author: Liuzhihan
* @Date: 2020-03-22 23:36:43
* @Last Modified by: Liuzhihan
* @Last Modified time: 2020-03-23 22:40:19
*/
/*
* F Find my Family
* 题目意思很直白,找出存在中间的数比左边的数小,右边的数比左边的数大,如果对于暴力求法,在 n
* 次情况下必定超时,此时就需要两个客观意义上的指针。首先解决右边的数,那么我们把第 i 个数以后
* 最大的数找出,就可以解决右边数的最大值,剩下的就是左边的数,我们可以同过 set 和二分来查找出
* 比当前 数恰好大一点的数, 若有,再用此数 和右边的最大数相比即可。这样最后的时间复杂度是
* O(nlogn)。
*/
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;
int T, n, t, h[maxn], max_h[maxn];
vector<int> ans;
int main()
{
scanf("%d", &T);
while (T--)
{
t++;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &h[i]);
max_h[n + 1] = 0;
for (int i = n; i >= 1; i--)
max_h[i] = max(h[i], max_h[i + 1]);
set<int> s;
s.clear();
s.insert(h[1]);
for (int i = 2; i < n; i++)
{
if (h[i] < max_h[i])
{
auto pos = s.upper_bound(h[i]);
if (pos != s.end() && *pos < max_h[i])
{
ans.push_back(t);
break;
}
}
s.insert(h[i]);
}
}
printf("%d\n", ans.size());
for (auto i : ans)
printf("%d\n", i);
return 0;
}