Codeforces C. Array Destruction (Round #696 Div.2)(构造&思维&贪心)

传送门

题意: 问是否能选定一个初始值x,使得能按一定要求消除掉大小为 n*2 的数组所有值。要求:第一次删除两个数的和为x,以后每次删除的两数之和都为上次删除数的max。问是否能正好删除数组的所有值,并输出构造的删除顺序。
在这里插入图片描述
思路:

  • 由于本题数据范围不大,可以考虑暴力的思维。
  • 每次删除的数必定是当前数组的最大值和另一个特定的数(两数之和必定等于上一轮删除的最大数),所以只要 x 确定后,之后的删除顺序便都确定了。
  • 而 x 就由第一次删除的两个数来决定,其中一个为整个数组的max,另一个便可以暴力枚举了。
  • 至于为什么每次都得删除当前数组最大值,这个就不言而喻了嘛。如果每次不删除最大值,之后就不可能再消除它了,毕竟下一次删除的和才到上一次的max。
  • 具体细节见代码注释。

代码实现:

#include<bits/stdc++.h>
#define endl '\n'
#define null NULL
#define ll long long
#define int long long
#define pii pair<int, int>
#define lowbit(x) (x &(-x))
#define ls(x) x<<1
#define rs(x) (x<<1+1)
#define me(ar) memset(ar, 0, sizeof ar)
#define mem(ar,num) memset(ar, num, sizeof ar)
#define rp(i, n) for(int i = 0, i < n; i ++)
#define rep(i, a, n) for(int i = a; i <= n; i ++)
#define pre(i, n, a) for(int i = n; i >= a; i --)
#define IOS ios::sync_with_stdio(0); cin.tie(0);cout.tie(0);
const int way[4][2] = {
    
    {
    
    1, 0}, {
    
    -1, 0}, {
    
    0, 1}, {
    
    0, -1}};
using namespace std;
const int  inf = 0x7fffffff;
const double PI = acos(-1.0);
const double eps = 1e-6;
const ll   mod = 1e9 + 7;
const int  N = 2e5 + 5;

int t, n, m, a[N];
map<int, int> ct, mp;
vector<int> b;

signed main()
{
    
    
    IOS;

    cin >> t;
    while(t --){
    
    
        cin >> m;
        n = m*2;
        ct.clear(); mp.clear(); b.clear();//更新所有中间数组
        for(int i = 1; i <= n; i ++){
    
    
            cin >> a[i];
            mp[a[i]] ++;
        }
        ct = mp;
        sort(a+1, a+n+1);
//        for(int i = 1; i <= n; i ++){
    
    
//            cout << "debug: " << a[i] << " " << ct[a[i]] << endl;
//        }
        int flag = 0, tmp = a[n], res;
        for(int i = 1; i < n; i ++){
    
    
            res = a[i]; ct[res] --; //枚举选定与首个max一起消除的另一个数
            b.push_back(res);
            b.push_back(a[n]);
            ct[a[n]] --;
            for(int j = n-1; ~j; j --){
    
    
                if(!j) {
    
    flag = 1; break;}  //表示所有数都已消除
                if(!ct[a[j]]) continue; //如果当前这个max已经不存在
//                cout << "tmp: " << tmp << endl;
//                cout << "debug: " << a[j] << " " << ct[a[j]] << " " << tmp-a[j] << " " << ct[tmp-a[j]] << endl;
                if(!ct[tmp-a[j]]||(ct[a[j]]==1&&tmp==a[j]*2)){
    
     //如果无法找到与当前max匹配的数,特别注意tmp==a[j]*2的情况
                    b.clear();
                    ct = mp;
                    tmp = a[n]; //恢复所有初始值
                    break;
                }
                else{
    
    
                    b.push_back(tmp-a[j]);
                    b.push_back(a[j]);  //先将两个数加入答案集合并从原先数集中消除
                    ct[a[j]] --; ct[tmp-a[j]] --;
                    tmp = a[j]; //更新当前max
                }
            }
            if(flag) break;
        }
        cout << (flag ? "YES":"NO") << endl;
        if(flag){
    
    
            cout << a[n]+res << endl;
            for(int i = 0; i < n; i += 2)
                cout << b[i] << " " << b[i+1] << endl;
        }
    }

    return 0;
}

后期看见一篇利用multiset的题解还比较好。

猜你喜欢

转载自blog.csdn.net/Satur9/article/details/112985057