舞蹈课
【问题描述】
有n 个人参加一个舞蹈课。每个人的舞蹈技术由整数来决定。在舞蹈课的开始,他们从
左到右站成一排。当这一排中至少有一对相邻的异性时,舞蹈技术相差最小的那一对会出猎并开
始跳舞。如果不止一对,那么最左边的那一对出列。一对异性出列之后,队伍中的空白按原顺序补上
(即:若队伍为ABCD,那么BC 出列之后队伍变成AD)。舞蹈技术相差最小即是|ai|最小。
你的任务是,模拟以上过程,确定跳舞的配对及顺序。
【输入】
第一行为正整数n(1<=n<=2*10^5),表示队伍中的人数。下一行包含n 各字符B 或G,表示男
孩还是女孩。下一行为n 个整数ai(ai<=10^7)。所有信息按照从左到右的顺序给出。在50%的数
据中,n<=200。
【输出】
第一行:出列的总对数k。接下来输出k 行,每行是两个整数,按跳舞顺序输出。两个整数代表
这一对舞伴的编号(按输入顺序从左往右1 至n 编号)。请先输出较小的整数,再输出较大的整数。
作为今天模拟赛的第三题 一看还觉得是数论啊什么的
后来发现是一道“普及+/提高”的模拟题
把所有相邻的异性加入队列 (优先队列 从大往小排 要注意字典序排序)
往后扫看是否能凑对
vist存是否配对过,while配对过直接跳过,直到两端或者不为配对过的就行了,还有就可以存两端位置,直接更新,有点像链的那种存储。
优先队列判定加个如果相等就取左边小的,很明显可以证明不可能存在交叉,所以一定是对的。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
using namespace std;
struct node
{
int x,y,c;
bool operator<(const node &p)const{
if(p.c==c)
{
return p.x<x;
}
return p.c<c;
}
};
priority_queue<node> line;
int cnt=0;
struct NODE
{
int x,y;
} partner[100005];
int n,a[200005];
bool vis[200005];
char c[200005];
int main()
{
freopen("dancinglessons.in","r",stdin);
freopen("dancinglessons.out","w",stdout);
scanf("%d",&n);
scanf("%s",c);
scanf("%d",&a[1]);
for(int i=2;i<=n;i++)
{
scanf("%d",&a[i]);
node t;
if(c[i-1]!=c[i-2])
{
t.x=i-1;
t.y=i;
t.c=fabs(a[i]-a[i-1]);//记录间距
line.push(t);
}
}
bool flag;
while(!line.empty())
{
flag=0;
node t=line.top();
line.pop();
if(vis[t.x]||vis[t.y]) continue;
partner[++cnt].x=t.x;
vis[t.x]=true;
partner[cnt].y=t.y;
vis[t.y]=true;
while(vis[t.x-1])
{
if(t.x<=2)
{
flag=1;
break;
}
t.x--;
}
if(flag==1)
continue;
while(vis[t.y+1])
{
if(t.y>=n-1)
{
flag=1;
break;
}
t.y++;
}
if(flag==1)
{
continue;
}
if(c[t.x-2]!=c[t.y]&&t.x>1&&t.y<n)
{
t.x=t.x-1;
t.y=t.y+1;
t.c=fabs(a[t.x]-a[t.y]);
line.push(t);
}
}
printf("%d\n",cnt);
for(int i=1;i<=cnt;i++)
{
printf("%d %d\n",partner[i].x,partner[i].y);
}
}
前面说了储存有点链的味道
所以也可以用堆+双向链表
将所有相邻异性加入堆(大根)
当队中还有元素时,取出并删除堆顶,否则结束
如果堆顶两个人出列了继续循环
将a和b标记为已出列检查a左边和b右边是否为异性如果是加入堆
将a和b从双向链表中删除
#include<stdio.h>
#include<stdlib.h>
#define abs(a) (a>0 ? (a):-(a))
int i,j,k,n,m,a[301000],top,b[301000],c[301000];
int f1[301000],f2[301000];
int ans[301000][2];
char s[301000];
void work(int h,int n)
{
int i=h,j=i*2,tmp=a[i],tmpf1=f1[i],tmpf2=f2[i],z=i;
while (j<=n){
//printf("%d %d %d %d\n",i,j,a[i],a[j]);
if (j<n&&(a[j]>a[j+1]||(a[j]==a[j+1]&&f1[j]>f1[j+1]))) j++;
if (tmp<a[j]||(tmp==a[j]&&tmpf1<f1[j]))
break;
a[i]=a[j];
f1[i]=f1[j];
f2[i]=f2[j];
i=j;
j*=2;
}
a[i]=tmp;
f1[i]=tmpf1;
f2[i]=tmpf2;
}
int main()
{
freopen("dancinglessons.in","r",stdin);
freopen("dancinglessons.out","w",stdout);
scanf("%d",&n);
getchar();
for (i=1;i<=n;i++)
scanf("%c",&s[i]);
for (i=1;i<=n;i++){
scanf("%d",&b[i]);
if (i!=1&&s[i]!=s[i-1])
top++,a[top]=abs(b[i]-b[i-1]),f1[top]=i-1,f2[top]=i;
}
for (i=top/2;i>=1;i--)
work(i,top);
for (i=1;i<=n/2;i++){
int flag=0;
while (!flag){
int x,y;
x=f1[1],y=f2[1];
if (c[x]==0&&c[y]==0){
c[x]=1,c[y]=1;
ans[i][0]=x,ans[i][1]=y;
flag=1;
while (c[x]==1&&x>=0) x--;
while (c[y]==1&&y<=n+1) y++;
if (x>0&&y<=n&&s[x]!=s[y]){
a[1]=abs(b[x]-b[y]);
f1[1]=x,f2[1]=y;
work(1,top);
}
}
else a[1]=a[top],f1[1]=f1[top],f2[1]=f2[top],top--,work(1,top);
if (top==0) break;
}
if (top==0) break;
}
k=0;
for (j=1;j<=i;j++)
if (ans[j][0]!=0)
k++;
printf("%d\n",k);
for (i=1;i<=k;i++)
printf("%d %d\n",ans[i][0],ans[i][1]);
return 0;
}