CodeForces-1185D Extra Element

题目链接:CodeForces-1185D Extra Element

题意

给出长度为$n$的序列,删除一个元素使得剩下的元素可以排列成等差数列,如果可以,输出删除元素的序号,如果不能,输出-1。


思路

由于只能删除一个元素,所产生的等差数列并不会有很多种可能,所以可以从公差入手,不必每个元素都去尝试删除。

$n==2$时必定有解,删除第一个元素即可。

$n>2$时可能的公差只有三种情况:

  1. 序列中第二小的数$-$最小的数;
  2. 序列中第三小的数$-$第二小的数;
  3. 序列中第三小的数$-$最小的数。

对于每种可能的公差遍历排序后的序列,统计要删除多少个数才能满足这个公差即可,删除的数量$<=1$表示有解。

边界情况可能要注意一下,如何处理看个人技巧和习惯。


代码实现

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <utility>
using std::pair;
using std::sort;
const int N = 200010;
pair<int, int> arr[N]; // first: 数组元素的值,second: 下标
// 计算数组[s,n)范围内要删除多少个才能满足公差为d,并把删除的数的原下标赋值给ans
int check(int d, int s, int n, int &ans) {
    int res = 0, pre = arr[s].first;
    for (int i = s + 1; i < n; i++) {
        if (arr[i].first - pre != d) ans = arr[i].second, res++;
        else pre = arr[i].first;
        if (res > 1) return res;
    }
    return res;
}
bool print(int tmp, int ans) {
    if (tmp == 1) return printf("%d\n", ans);
    else if (tmp == 0) return printf("%d\n", arr[0].second);
    return false;
}

int main() {
    int n;
    while (~scanf("%d", &n)) {
        for (int i = 0; i < n; i++) {
            scanf("%d", &arr[i].first);
            arr[i].second = i + 1;
        }
        if (n == 2) {
            puts("1");
            continue;
        }
        sort(arr, arr + n);
        int ans, tmp;
        // 公差为第二小的数减最小的数
        tmp = check(arr[1].first - arr[0].first, 0, n, ans);
        if (print(tmp, ans)) continue;
        // 公差为第三小的数减第二小的数
        tmp = check(arr[2].first - arr[1].first, 1, n, ans);
        if (tmp == 0) { printf("%d\n", arr[0].second); continue; }
        // 公差为第三小的数减最小的数
        tmp = check(arr[2].first - arr[0].first, 0, n, ans);
        if (!print(tmp, ans)) puts("-1");
    }
    return 0;
}
View Code

 

posted @ 2019-08-13 13:20  _kangkang  阅读(211)  评论(0编辑  收藏  举报