首页 > 技术文章 > CF1474-C. Array Destruction

chantmee 2021-01-20 21:18 原文

CF1474-C. Array Destruction

题意:

题目给出一个长度为\(2n\)的正整数序列,现在问你是否存在一个\(x\)使得可以不断的进行如下操作,直到这个序列变为空:

从序列中找到两个数字\(a_1,a_2\),使得\(a_1+a_2==x\),然后从序列中删掉这两个数字,\(x\)的值也被更新,\(x=max(a_1, a+2)\)


题解:

由于这道题给的数据范围较小\(n\leqslant1000\),所以可以通过暴力枚举\(x\)来得到答案。

当然这里暴力枚举\(x\)也有一定的技巧。先说结论,这个最开始的\(x\)一定等于序列中最大的一个数字\(a_{max}\)加上序列中的另外一个数字\(a_i\),原因如下:

假设\(x\not=a_{max}+a_i\),也就是说\(x=a_{i_1}+a_{i_2}, max\{a_{i_1},a_{i_2}\}<a_{max}\),那么当从序列中找到了\(a_{i_1},a_{i_2}\)之后\(x\)就被更新为\(x=max\{a_{i_1},a_{i_2}\}\),这个时候\(a_{max}\)是大于\(x\)的,\(x\)不可能在这之后加上一个正整数之后等于\(a_{max}\),因为这之后,\(x\)一直保持递减的状态。

由此,\(x\)枚举的值可以为\(a_{max}+a_{i},1\leqslant i\leqslant n-1\),对于每个枚举的\(x\)

每次找到序列中的最大值\(a_{max}\)然后二分搜索\(x-a_{max}\),删掉这两个数字,然后更新\(x\)... ...如果每次都能找到\(x-a_{max}\)这个值并最终将整个序列删掉,那么这个\(x\)就是答案,如果全部\(x\)枚举完都没有答案,那么就不存在。


AC代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>

#define pii pair<int, int>
#define mp(a, b) make_pair(a, b)
#define fr first
#define sc second

const int Maxn = 2005;

std::vector<std::pii>ans;
int a[Maxn];
bool vis[Maxn];

bool check(int t, int n) {
    ans.clear();
    ans.push_back(std::mp(t, 0));
    memset (vis, 0, sizeof vis);
    int cur = n;
    while (cur > 0) {
        int pos_1 = -1;
        for (int i = n - 1; i >= 0; i--) {
            if (!vis[i]) {
                pos_1 = i;
                vis[pos_1] = true;
                break;
            }
        }
        int pos_2 = (int)(std::lower_bound(a, a + n, t - a[pos_1]) - a);
        while (pos_2 < n && vis[pos_2]) {
            pos_2++;
        }
        if (pos_2 == n || a[pos_1] + a[pos_2] != t || vis[pos_2]) {
            return false;
        }
        vis[pos_2] = true;
        t = a[pos_1];
        cur -= 2;
        ans.push_back(std::mp(a[pos_1], a[pos_2]));
    }
    return true;
}

void solve() {
    int n;
    scanf("%d", &n);
    for (int i = 0; i < 2 * n; i++) {
        scanf("%d", &a[i]);
    }
    std::sort (a, a + 2 * n);
    bool flag = false;
    for (int i = 0; i + 1 < 2 * n; i++) {
        int t = a[i] + a[2 * n - 1];
        flag = check(t, 2 * n);
        if (flag) {
            break;
        }
    }
    if (!flag) {
        printf("NO\n");
    } else {
        printf("YES\n%d\n", ans[0].fr);
        for (int i = 1; i < ans.size(); i++) {
            printf("%d %d\n", ans[i].fr, ans[i].sc);
        }
    }
}

int main() {
    int T;
    scanf("%d", &T);
    while(T--) {
        solve();
    }

    return 0;
}

推荐阅读