跳过正文
题解:CF45C Dancing Lessons

题解:CF45C Dancing Lessons

xyx404
作者
xyx404
Have a nice day.

封面

思路:
#

定义结构体,结构体包含三个成员 $left$ 表示左边的人,$right$ 表示右边的人,$cz$ 表示这两个人的差值,自定义排序:

bool operator <(const node &X)const{
  return cz==X.cz?left>X.left:cz>X.cz;
}

定义优先队列,类型为上面定义的结构体。
定义标记数组 $bj$ 标记这个人是否已经被搭配了。
定义二维数组 $ans$ 存答案。
定义 $ans2$ 存答案的数量。
定义数组 $last$ 和 $nex$ 模拟链表,记录上一个人和下一个人。

在输入时顺便把 $last$ 和 $nex$ 初始化,初始化时 $last_i$ 的值为 $i-1$,$nex_i$ 的值为 $i+1$。

在输入完后,遍历字符串,直到现在遍历到的是字符串的最后一个字母,注意是遍历到而不是遍历完,当字符串的第 $i$ 个字符与第 $i+1$ 个字符不同时,也就是他们为异性时,把他们及他们的差值的绝对值存进结构体加入优先队列。

然后进入循环,循环条件为队列不为空,在循环内,先把队列里的结构体取出来,然后弹出,然后判断下,取出来的结构体里的 $left$ 和 $right$ 是否在 $bj$ 里被标记过,如果其中有一个被标记过那么直接开始下一次循环,否则标记他们,并把他们存在 $ans$ 数组里,并让 $ans2$ 加一,在这之后维护链表,如果去掉他们两个后,$left$ 原本的左边的人与 $right$ 原本右边的人为异性那么把他们与他们的差值的绝对值存进结构体加入优先队列。

最后先输出 $ans2$,然后把 $ans$ 数组里被存过的答案输出就行了。

代码:
#

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define itn int
#define ull unsigned long long
int last[200005],nex[200005],a[200005],ans[200005][3],ans2;
struct node{
	itn left,right,cz;
	bool operator <(const node &X)const{
		return cz==X.cz?left>X.left:cz>X.cz;
	}
};
priority_queue<node>dl;
bool bj[200005];
string str;
itn n;
int main(){
	cin>>n>>str;
	str=" "+str;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		last[i]=i-1;
		nex[i]=i+1;
	}
	for(int i=1;i<n;i++){
		if(str[i]!=str[i+1]){
			dl.push(node{i,i+1,abs(a[i]-a[i+1])});
		}
	}
	while(!dl.empty()){
		node tamp=dl.top();dl.pop();
		if(bj[tamp.left]||bj[tamp.right])continue;
		ans[++ans2][1]=tamp.left;
		ans[ans2][2]=tamp.right;
		bj[tamp.left]=bj[tamp.right]=1;
		int l=last[tamp.left],ne=nex[tamp.right];
		nex[l]=ne;last[ne]=l;
		if(l<1||ne>n)continue;
		if(str[l]!=str[ne]){
			dl.push(node{l,ne,abs(a[l]-a[ne])});
		}
	} 
	cout<<ans2<<"\n";
	for(itn i=1;i<=ans2;i++){
		cout<<ans[i][1]<<" "<<ans[i][2]<<"\n";
	}
	return 0;
}