『题解』CodeForces CF27C Unordered Subsequence
题目大意
给定一个长度为 \(n\) 的序列,请找出最短的非有序的子序列。子序列可以不连续。
有序定义如下:如果一个序列是递增的或递减的(相等也算增和降),则是有序的。
输出最短非有序子序列的长度,并输出这些数的下标。
思路
首先,可以排除长度 \(\le 2\) 的情况,因为长度 \(\le 2\) 的序列一定是有序的。然后就要看长度 \(\ge 3\) 的情况了。若为 \(3\),则是最优情况。若为 \(4\),我们可以通过删去一个元素,变成长度为 \(3\) 的序列,可以发现,长度为 \(4\) 的序列始终可以通过删去一个元素还是保持非有序。当长度 \(\ge 5\) 时,同上,也可以化简为长度为 \(3\) 的非有序序列。
于是,题意就化简为:找到长度为 \(3\) 的非有序子序列。
如果暴力枚举 \(3\) 个点,那一定会超时,时间复杂度 \(\mathcal{O}(n^3)\)。
先来分析一下长度为 \(3\) 的序列非有序的条件。若有两个数相等,那么一定是最左边和最右边的数,不可能连在一起。递增或递减也不行,包括全部相等。那就只有两种可能:小大小
和 大小大
的情况。稍微想一想,就很能明白了。
我们可以假定下标为 \(1\) 的数是第一个数,搜一遍数组,找连续两个数作为另外两个数。然后判断,按照上面的分析,判断条件也很容易得出:a[1]<a[i] && a[i]>a[i+1] || a[1]>a[i] && a[i]<a[i+1]
。若条件成立,则已经找到正确答案,输出并退出程序。若始终没有找到正确答案,那么就无解。
代码
#include <iostream>
using namespace std;
int n,a[100005];
int main(){
cin >> n;
for(int i=1; i<=n; i++){
cin >> a[i];
}
for(int i=2; i<n; i++){
// 中间的最大或最小,都算可以。
if(a[1]<a[i] && a[i]>a[i+1] || a[1]>a[i] && a[i]<a[i+1]){
cout << "3\n1 " << i << " " << i+1 << endl;
return 0;
}
}
puts("0"); // 没找到则无解
return 0;
}