题解:CF45C Dancing Lessons

封面

思路:

定义结构体,结构体包含三个成员 leftleft 表示左边的人,rightright 表示右边的人,czcz 表示这两个人的差值,自定义排序:

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

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

在输入时顺便把 lastlastnexnex 初始化,初始化时 lastilast_i 的值为 i1i-1nexinex_i 的值为 i+1i+1

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

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

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

代码:

#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;
}