『题解』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;
}
posted @ 2022-01-21 21:14  仙山有茗  阅读(30)  评论(0编辑  收藏  举报