【CF补题】【D】Educational Codeforces Round 131 (Rated for Div. 2) C++代码

本文介绍了如何使用贪心策略解决D.PermutationRestoration问题,通过分析给定条件并利用STL数据结构,实现对n个区间内的数进行合理分配,确保每个区间选取的数满足特定范围。关键在于优先级排序和利用lower_bound操作找到合适位置的数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

D. Permutation Restoration

解法:贪心算法

分析:我们来分析第i个位置的a[i]的可能情况,发现有:

i/(b[i-1]+1)+1<=a[i]<=i/b[i]

我们有n个可能取值的区间,其中区间左右边界均小于等于n,让我们在每个区间中选取一个数,且要保证任意两个区间内选取的数不能相同,任意构造出来一组解即可。

这是一个比较经典的问题,按照贪心的思想来想,我们首先要按照n个区间的右区间从小到大进行排序,右区间越小我们越应该先给该区间分配一个数,因为我们是从小到大考虑每个数,在右区间相同的前提下我们再按照左区间从小到大排序,这也是容易理解的,

我们优先考虑 l[i] 是否能作为第i个区间所选取的数,因为在第i个区间之后的区间不一定包含l[i],而且即使包含l[i],那么这个区间的区间右边界也一定大于等于当前区间右边界,所以比当前区间的选数可能性更多,这是由于排序规则决定的,所以我们只需要从每个区间左边界开始遍历,一直到该区间右边界,当一个数尚未被选时我们就选他。

如果直接遍历是会超时的,这时候我们可以;利用STL!

set<int>rest;

for (int i = 1; i <= n; i++)  rest.insert(i);

ans[p[i].id] = *rest.lower_bound(p[i].l);

rest.erase(ans[p[i].id]);用一个删一个。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int mo = 1e3;
const int N = 5e5 + 5;
int a[N], b[N], ans[N], vis[N];
struct str
{
	int id, l, r;
} p[N];
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin >> t;
	while (t--)
	{
		int n;
		cin >> n ;
		set<int>rest;
		for (int i = 1; i <= n; i++)
		{
			rest.insert(i);
			cin >> b[i];
			p[i].id = i;

			if (b[i] != 0)
			{
				p[i].r = i / b[i];
				p[i].l = (i / (b[i] + 1)) + 1;
			}
			else
			{
				p[i].l = i + 1;
				p[i].r = n;
			}
		}
		sort(p + 1, p + n + 1, [&](str x, str y)
		{
			if (x.r == y.r)return x.l < y.l;
			return x.r < y.r;
		});

		for (int i = 1; i <= n; i++)
		{
			ans[p[i].id] = *rest.lower_bound(p[i].l);
			rest.erase(ans[p[i].id]);
		}
		for (int i = 1; i <= n; i++)
		{
			cout << ans[i] << ' ';
		}
		cout << '\n';
	}

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值