题目
给出k(最大5000)个不同整数组成的序列,判断是否存在4个整数 Np,Nq,Nr,Ns(1<=p<q<r<s<=k) N p , N q , N r , N s ( 1 <= p < q < r < s <= k ) ,使得 Np<Ns<Nq<Nr N p < N s < N q < N r 或者 Np>Ns>Nq>Nr N p > N s > N q > N r 。
思路
枚举方法,假设一种情况:
序号:p,q,r,s
大小:q>s>p>r
1.首先枚举p。原因是p序号最小,都能用得上H[maxn], L[maxn]。
2. 再枚举q,q在H[p]中枚举。
3. 再确定r,在L[p]中查找第一个序号大于q的,即为r。原因是,r的大小对最后s的枚举没影响,而r的序号应越小越好,才能给s的枚举腾出更多序号可选空间。(贪心)
4. 最后枚举s,s满足在L[q]和H[p]的交集中,且满足序号小于r。
全部枚举完,就可以return true。
理论复杂度为O(n*nO(n3),陈锋的这个方法个人感觉并不快,但还是AC了。
本题感觉,就在于技巧枚举,如何枚举使r不需要枚举,减少一个次方的复杂度,就很好写了。另外一个,vector数组在数据不多的题目的运用。
代码
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <algorithm>
#define _for(i,a,b) for(int i = (a); i<(b);i++)
#define _rep(i,a,b) for(int i = (a); i<=(b);i++)
using namespace std;
int readin() { int x; scanf("%d", &x); return x; } // 简化版输入
const int maxn = 5000 + 100;
int n, A[maxn];
vector<int> H[maxn], L[maxn]; // 存储的是下标
//higher和lower, 表示点i后面比它大的元素组成的序列,比它小的元素组成的序列
bool solve1(int p) {
for (vector<int>::iterator q = L[p].begin(); q != L[p].end(); ++q) {
vector<int>::iterator r = lower_bound(H[p].begin(), H[p].end(), *q);
if (r == H[p].end()) continue;
vector<int>::iterator s = lower_bound(L[p].begin(), L[p].end(), *r);
while (s != L[p].end()) {
if (binary_search(H[*q].begin(), H[*q].end(), *s)) return true;
++s;
}
}
return false;
}
bool solve2(int p) {
for (vector<int>::iterator q = H[p].begin(); q != H[p].end(); ++q) {
vector<int>::iterator r = lower_bound(L[p].begin(), L[p].end(), *q);
if (r == L[p].end()) continue;
vector<int>::iterator s = lower_bound(H[p].begin(), H[p].end(), *r);
while (s != H[p].end()) {
if (binary_search(L[*q].begin(), L[*q].end(), *s)) return true;
++s;
}
}
return false;
}
void init() {
_for(i, 0, n) {
L[i].clear();
H[i].clear();
}
}
int main() {
int T = readin();
while (T--) {
n = readin();
_for(i, 0, n) A[i] = readin();
// 对H, L进行打表
init();
_for(i, 0, n)
_for(j, i + 1, n)
if (A[j] > A[i]) H[i].push_back(j);
else if (A[j] < A[i]) L[i].push_back(j);
// 首先对P进行枚举,因为P的序号最小,才能用得上H和L
bool success = false;
_for(p, 0, n)
if (solve1(p) || solve2(p)) {
success = true;
break;
}
if (success) printf("YES\n");
else printf("NO\n");
}
return 0;
}