C. Elemental Decompress codeforces 1768C

11 篇文章 0 订阅
该篇文章介绍了一种算法问题,要求根据给定数组构建两个排列p和q,使得每个元素的最大值等于原数组中的值。通过统计元素出现次数,使用大根堆处理未出现过的数字,并按特定顺序填充p和q数组,确保每个元素在p和q中各出现一次且满足最大值条件。
摘要由CSDN通过智能技术生成

Problem - C - Codeforces

题目大意:给出一个长度为n的数组a,要求输出两个排列p,q,使得对于所有i属于1到n,都有max(pi,qi)=ai

1<=n<=2e5;1<=ai<=n

思路:我们可以发现如果一个数字在a中出现了两次,那么p中一个位置需要这个数字,另一个位置就是要q中是这个数字,那么我们统计a中数字出现的次数,如果是第一次出现就让p中对应位置的数字等于它,第二次出现时就让q中对应位置的数字等于它,然后我们如果这个位置更新的p,就要记录对这个位置pi的值和数组下标,作为以后构造q数组的依据,同时分别记录哪些数字没有在排列p,q,中现过,然后我们将这些没有访问过的值放入大根堆中,并将之前记录的对组数组按数值排序,从大到小遍历,并依次将大根堆中的数放入即可,例如4,3,2,1在q中没有出现过,然后我们记录过p中5,4,3,2的位置,那么我们就从大到小依次让p中5,4,3,2的位置分别在q中放入4,3,2,1,最后再检验构造的两个数组是否满足排列的要求和最大值等于a的要求

//#include<__msvc_all_public_headers.hpp>
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int cnt[N];
int a[N], b[N];
pair<int,int> aa[N], bb[N];
int cnta[N], cntb[N];
int ma[N];
bool visa[N], visb[N];
int main()
{
	cin.tie(0);
	ios::sync_with_stdio(false);
	int t;
	cin >> t;
	while (t--)
	{
		int n;
		cin >> n;
		bool flag = 1;
		for (int i = 1; i <= n; i++)
		{
			a[i] = b[i] = 0;//p,q数组
			cnt[i] = 0;//统计a中数字出现的次数
			cnta[i] = cntb[i] = 0;//统计构造好的数组中数字出现的次数
			visa[i] = visb[i] = 0;//统计哪些数字已经被添加进了p,q中
		}
		int tota = 0, totb = 0;
		for (int i = 1; i <= n; i++)
		{
			cin >> ma[i];
			cnt[ma[i]]++;
			if (cnt[ma[i]] == 1)
			{//第一次出现的,放入p中
				a[i] = ma[i];
				bb[++totb] = make_pair(ma[i], i);//记录数值,下标
				visa[ma[i]] = 1;
			}
			else
			{
				b[i] = ma[i];
				aa[++tota] = make_pair(ma[i], i);
				visb[ma[i]] = 1;
			}
		}
		priority_queue<int>qa, qb;//存放没被添加过的数
		for (int i = 1; i <= n; i++)
		{
			if (!visa[i])
				qa.push(i);
			if (!visb[i])
				qb.push(i);
		}
		sort(aa + 1, aa + 1 + tota);
		sort(bb + 1, bb + 1 + totb);//按数值排序
		for (int i = tota; i >= 1; i--)
		{//从大到小遍历
			a[aa[i].second] = qa.top();//依次取出堆顶数,放入对应下标的位置上
			qa.pop();
		}
		for (int i = totb; i >= 1; i--)
		{
			b[bb[i].second] = qb.top();
			qb.pop();
		}
		for (int i = 1; i <= n; i++)
		{
			cnta[a[i]]++;//统计构造好的数组中每个数出现的次数
			cntb[b[i]]++;
		}
		for (int i = 1; i <= n; i++)
		{
			if (cnta[i] != 1 || cntb[i] != 1||max(a[i],b[i])!=ma[i])
			{//每个数是否出现次数都是1,pi,qi最大值是都等于ai
				flag = 0;
				break;
			}
		}
		if (!flag)
		{
			cout << "NO" << endl;
			continue;
		}
		cout << "YES" << endl;
		for (int i = 1; i <= n; i++)
		{
			cout << a[i]<<" ";
		}
		cout << endl;
		for (int i = 1; i <= n; i++)
		{
			cout << b[i] << " ";
		}
		cout << endl;
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

timidcatt

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值