Codeforces Round #842 (Div. 2)-C. Elemental Decompress

题目:
在这里插入图片描述
题目大意: 给定一个数列t,你构造两个数列a和b,使得max(a[i],b[i])=t[i]

核心思想: 1、先根据给出的数组进行放置,优先放到a数组中,如果这个数已经在a数组中出现了,再去放到b数组中
注意:a和b均为permutations ,也即1~n在a中必须出现,且只出现一次。
2、接下来先补全a数组:
把a数组中未出现的从大到小排序(用大根堆优先队列),记为t1
b数组中已经出现的从大到小排序(用sort排序)并记录下标,记为t2
因为这时两个都已经排好序了,最贪心的做法就是,把a最大的放到b最大的数所记录的下标位置 ,接着把a第二大的放到b第二大的数所记录的下标位置 ,接着把a第三大的放到b第三大的数所记录的下标位置……
这时一定是最优的,如果在放置的过程中,发现有个a中有个数比b的大,则之后的一定都比b的大,题目条件一定不满足
3、接下来先补全b数组(和上面类似):
把b数组中未出现的从大到小排序(用大根堆优先队列),记为t1
a数组中已经出现的从大到小排序(用sort排序),记为t2
如果能满足,则对于每一个t1[i],一定小于或等于t2[i]

AC代码:

#include <bits/stdc++.h>
using namespace std;
#define de(x) cout << x << " ";
#define sf(x) scanf("%d", &x);
#define Pu puts("");
#define ll long long
const int N = 2e5 + 10, M = 1e3 + 10;
int n, m, k, ans;
int a[N], b[N];
// a,b数组为最终的结果数组
bool st[N];
// st[i]为0时表示a数组i处已经放了,为1时表示b数组i处已经放了
bool v1[N], v2[N];
// v1[x]表示a数组中目前已经出现了x;v2[x]表示b数组中目前已经出现了x
struct E {
    int u, id;
} t[N];
int cn;
bool cmp(E a, E b) {
    return a.u > b.u;
}
int main() {
    int T;
    cin >> T;
    int x;
    priority_queue<int> q;
    while (T--) {
        cin >> n;
        memset(v1, 0, sizeof(v1));  // 初始化
        memset(v2, 0, sizeof(v2));
        memset(st, 0, sizeof(st));
        int f = 1;  // 记录这次数组是否能满足
        for (int i = 1; i <= n; i++) {
            sf(x);
            if (v1[x] == 0) {
                v1[x] = 1;

                a[i] = x;
                st[i] = 0;  // a数组i处已经放了
            } else {
                // 注意这里需要判断一下,如果某个数在a数组和b数组都已经放过了(即出现第三次)
                // 则此时一定不满足
                if (v2[x] == 1) {
                    f = 0;
                }
                v2[x] = 1;

                b[i] = x;
                st[i] = 1;  // b数组i处已经放了
            }
        }
        if (f == 0) {
            printf("NO\n");
            continue;
        }

        // 1、接下来补全a数组:
        while (q.size())
            q.pop();
        cn = 0;
        for (int i = 1; i <= n; i++) {
            if (v1[i] == 0) {
                q.push(i);  // 找出a中没有出现的,放到优先队列中
            }
            if (st[i] == 1) {
                t[++cn].id = i;  // 找出b中已经出现的,放到结构体中
                t[cn].u = b[i];  // 记录下标
            }
        }
        sort(t + 1, t + cn + 1, cmp);  // 结构体按照存储的数字从大到小排序
        for (int i = 1; i <= cn; i++) {
            if (q.top() > b[t[i].id]) {
                f = 0;
                break;  // 如果此时b中已经出现过的小于a中未出现过的,则一定不满足
            }
            a[t[i].id] = q.top();  // 否则,把当前队列中最大的数补到a中
            q.pop();
        }
        if (f == 0) {
            printf("NO\n");
            continue;
        }

        // 2、接下来补全b数组:
        while (q.size())
            q.pop();
        cn = 0;
        for (int i = 1; i <= n; i++) {
            if (v2[i] == 0) {
                q.push(i);
            }
            if (st[i] == 0) {
                t[++cn].id = i;
                t[cn].u = a[i];
            }
        }
        sort(t + 1, t + cn + 1, cmp);
        for (int i = 1; i <= cn; i++) {
            if (q.top() > a[t[i].id]) {
                f = 0;
                break;
            }
            b[t[i].id] = q.top();
            q.pop();
        }
        if (f == 0) {
            printf("NO\n");
            continue;
        }

        printf("YES\n");
        for (int i = 1; i <= n; i++) {
            printf("%d ", a[i]);
        }
        Pu;
        for (int i = 1; i <= n; i++) {
            printf("%d ", b[i]);
        }
        Pu;
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值