枚举四个肯定是不行的,所以要枚举两个,我选择枚举中间的两个数,一个最大,一个最小。
另外,两种情况如果将数组翻转过来就可以相互等效,所以我只考虑第一种——2413 (从小到大排序)
为什么称为分段呢。。。你将会看到这是有道理的。
设l[i][j] 是DP式,若i小于j,可分为data【i】< data【j】与 data【i】> data【j】两种,
若i 大于 j,又可分为data【i】< data【j】与 data【i】> data【j】两种。并且这些情况都能在同一个二维数组里实现。
定义: L[i][j] 若i小于j并且data[i]>data[j],L[i][j]为下标小于i并且data值位于i与j之间的最小值的下标,如果没有就标为零。
若i小于j并且data[i]<data[j],L[i][j]为下标小于i并且data值比j大的最小值的下标,如果没有就标为零。
当i大于j时也类似定义(想一想吧...)
所以Dp过程有点复杂,不多说了,自己看代码。
这样只要枚举i 和 j (i<j,data[i]>data[j])在查询L[i][j] 和 L[j][i],分别表示的是下标小于i的data值(满足大于data[j] 并小于data[i]的)最小的 下标 和 下标大于j的 data
值(满足大于data[j] 并小于data[i]的)最大值的下标,在比较两个值的大小。。
AC代码(可能是uva上最好的算法,就是有点复杂。Run time 和第一的一样啊,都是0.016s)
#include <algorithm>
#include <cstdio>
#include <cctype>
using namespace std;
const int Main = 5000 + 50;
int l[Main][Main],data[Main];
int G() {
char ch;
int u(0);
do ch=getchar(); while(!isdigit(ch) );
u = ch - 48;
while(isdigit(ch=getchar())) u = u*10 + ch-48;
ungetc(ch,stdin);
return u;
}
int main()
{
int T, n;
T = G();
while(T--) {
bool rev(0);
int p,q;
n = G();
for(int i(1); i <= n; i++) data[i] = G();
for(int i=1;i<=n; i++) l[1][i] = l[n][i] = 0;
do {
for(int i = 2; i <= n-2; i++)
for(int j = i+1; j <= n-1; j++)
{
if(data[i] < data[j])
{
l[i][j] = l[i-1][j] ? l[i-1][j] : data[i-1] > data[j] ? i-1 : 0;
}else {
if(data[j] < data[i-1] && data[i-1] < data[i]) {
l[i][j] = l[i-1][j] ? l[i-1][j] : i-1;
}else {
if(!l[i-1][j]) l[i][j] = 0;
else l[i][j] = data[l[i-1][j]] < data[i] ? l[i-1][j] : 0;
}
}
}
for(int i = n-1; i >= 3; i--)
for(int j = i-1; j >= 2; j--)
{
if(data[i] > data[j])
{
l[i][j] = l[i+1][j] ? l[i+1][j] : data[i+1] < data[j] ? i+1 : 0;
}else {
if(data[i] < data[i+1] && data[i+1] < data[j])
l[i][j] = l[i+1][j] ? l[i+1][j] : i+1;
else {
if(!l[i+1][j]) l[i][j] = 0;
else l[i][j] = data[l[i+1][j]] > data[i] ? l[i+1][j] : 0;
}
}
}
for(int U = 2; U <= n-2; U++)
for(int V = U+1; V <= n-1; V++)
{
if(data[U] < data[V]) continue;
if(!l[U][V]) continue; else p = l[U][V];
if(!l[V][U]) continue; else q = l[V][U];
if(data[p] < data[q]) goto ext;
}
rev^=1;
if(rev) reverse(data+1,data+1+n);
}while(rev);
printf("NO\n");
continue;
ext:;
printf("YES\n");
}
return 0;
}