洛谷 P1878 舞蹈课(优先队列 + 双链表)

舞蹈课

题目描述

n n n 个人参加一个舞蹈课。每个人的舞蹈技术由整数来决定。在舞蹈课的开始,他们从左到右站成一排。当这一排中至少有一对相邻的异性时,舞蹈技术相差最小的那一对会出列并开始跳舞。如果不止一对,那么最左边的那一对出列。一对异性出列之后,队伍中的空白按原顺序补上(即:若队伍为 ABCD,那么 BC 出列之后队伍变为 AD)。舞蹈技术相差最小即是 a i a_i ai 的绝对值最小。

任务是模拟以上过程,确定跳舞的配对及顺序。

输入格式

第一行一个正整数 n n n 表示队伍中的人数。

第二行包含 n n n 个字符 B 或者 GB 代表男,G 代表女。

第三行为 n n n 个整数 a i a_i ai。所有信息按照从左到右的顺序给出。

输出格式

第一行一个整数表示出列的总对数 k k k

接下来 k k k 行,每行是两个整数。按跳舞顺序输出,两个整数代表这一对舞伴的编号(按输入顺序从左往右 1 1 1 n n n 编号)。请先输出较小的整数,再输出较大的整数。

样例 #1

样例输入 #1

4
BGBG
4 2 4 3

样例输出 #1

2
3 4
1 2

提示

对于 50 % 50\% 50% 的数据, 1 ≤ n ≤ 200 1\leq n\leq 200 1n200

对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 2 × 1 0 5 1\leq n\leq 2\times 10^5 1n2×105 1 ≤ a i ≤ 1 0 7 1\le a_i\le 10^7 1ai107

题意:

如题。

思路:

题目要求绝对值相差最小的一对异性出列,观察数据范围,显然要用到优先队列控制时间复杂度。

且题目要求对原序列进行删除和拼接,考虑用双链表实现这一点(时间复杂度 O(1)

代码:

#define _CRT_SECURE_NO_WARNINGS 1
#include <bits/stdc++.h>

using namespace std;
#define int long long
typedef pair<int, int> pii;
#define x first
#define y second
const int N = 2e5 + 10;
int n;
string qu;
int a[N];
bool st[N];

int e[N], l[N], r[N], idx;

//初始化
void init()
{
	l[1] = 0, r[0] = 1;//初始化 第一个点的右边是 1 第二个点的左边是 0
	idx = 2;//idx 此时已经用掉两个点了
}

//在第 K 个点右边插入一个 X 
void add(int k, int x)
{
	e[idx] = x;
	l[idx] = k;
	r[idx] = r[k]; //todo 这边的 k 不加 1  输入的时候 k+1 就好
	l[r[k]] = idx;
	r[k] = idx;
	idx++;
}//当然在K的左边插入一个数 可以再写一个,也可以直接调用我们这个函数,在k的左边插入一个 数,等价于在l[k]的右边插入一个数add(l[k],x)

//*删除第k个点
void remove(int k)
{
	r[l[k]] = r[k];
	l[r[k]] = l[k];
}

struct node
{
	int idx1, idx2;
	int dif;
	bool operator< (const node& x)const {
		if (dif == x.dif) return idx1 > x.idx1;
		return dif > x.dif;
	}
};
 
signed main()
{
	int T = 1; //cin >> T;

	while (T--)
	{
		init();
		cin >> n >> qu;
		qu = " " + qu;
		for (int i = 1; i <= n; ++i) scanf("%lld", &a[i]), add(i, a[i]);

		priority_queue<node> heap;
		for (int i = 1; i <= n - 1; ++i)
		{
			if (qu[i] != qu[i + 1])
			{
				heap.push({ i, i + 1, abs(a[i] - a[i + 1]) });
			}
		}

		int k = 0;
		vector<pii> ans;
		while (heap.size())
		{
			auto t = heap.top(); heap.pop();
			if (st[t.idx1] || st[t.idx2]) continue;
			++k;
			ans.push_back({ t.idx1, t.idx2 });
			
			if (l[t.idx1] && r[t.idx2] != (n + 1) && qu[l[t.idx1]] != qu[r[t.idx2]])
			{
				heap.push({ l[t.idx1], r[t.idx2], abs(a[l[t.idx1]] - a[r[t.idx2]]) });
			}
			remove(t.idx1), remove(t.idx2);
			st[t.idx1] = st[t.idx2] = true;			
		}

		cout << k << '\n';
		for (auto v : ans)
		{
			printf("%lld %lld\n", v.x, v.y);
		}
	}

	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值