晚会舞蹈 题解
题目来源:QZEZOJ
题目传送门
题目描述
晚会上有好多小伙伴,准备开始一场舞蹈。
舞蹈是2 个人一起跳的,而且是一男一女。
规定所有的人都站成了一排跳舞。
这一排人的顺序满足两点:
①对于任何一对舞伴,男生一定在女生的左边方向。
②任何一对舞伴之间,要么没有人,要么就有若干对舞伴。
其中女生知道自己左边有几个男生。
现在就请你再告诉这些女生,她们的舞伴距离她们多远(指包括那个男生,一共有多少男生夹在这对舞伴之间)。
输入
第一行为一个数N,表示参与的女生个数。
第二行\(N\) 个数,第i个数为\(A_i\),表示从左往右数的第\(i\)个女生左边共有\(A_i\)个男生;
输出
输出共一行\(N\)个数,每两个整数之间用一个空格隔开,行末无空格。表示\(N\) 个女生与其舞伴的距离。
样例输入
6
4 5 6 6 6 6
样例输出
1 1 1 4 5 6
提示
对于\(30\%\)的数据: \(1≤N≤50\);
对于\(50\%\)的数据: \(1≤N≤2,000\);
对于\(100\%\)的数据:\(1≤N≤500,000\);\(1≤A_i≤A_j≤N\)(\(1≤i<j≤N\));数据保证合法,不必验错。
题目解析
先来看一看样例解释:

这里菱形表示的是男生,三角形表示的是女生,一组舞伴用一条曲线连起来,这样答案就很显然了。
预处理
我们看一看输入的是什么:
第二行\(N\)个数,第i个数为\(A_i\),表示从左往右数的第\(i\)个女生左边共有\(A_i\)个男生;
输入的数不方便操作,我们就可以把它转化成类似于上图的样子。
这里将输入的数组\(x\)转化为数组\(a\).
我们用变量\(k\)来统计左端男生的个数,如果到达一定数量了,就放一个女生就可以了。这里用\(1\)来表示女生,\(2\)表示男生。
代码:
void pre(void){
for(i=j=k=1;i<=2*n;i++){
if(j==x[k]+1){
k++;
a[i]=1;//女生
}
else{
j++;
a[i]=2;//男生
}
}
return;
}
计算
预处理好之后,就开始计算了。
先看看数据,\(n \leq 500,000\) ,比较大,\(O\left( N^2\right)\)会炸掉,不能等出现女生在开始找,所以,我们可以用空间换时间,开一个栈,记录下男生的位置就可以了。这样可以实现\(O\left(N \right)\)的复杂度了。
memset(x,0,sizeof(x));
k=0;
for(int i=1;i<=2*n;i++){
if(a[i]==2){
k++;
x[k]=i;
}
else{
printf("%d ",(int)ceil((i-x[k])/2.0));
k--;
}
}
放一下你们最爱的AC代码:
#include<cstdio>
#include<cstring>
#include<cmath>
#define maxn 5000039
using namespace std;
int x[maxn],a[maxn<<1];
int n,i,j,k;
void pre(void){
for(i=j=k=1;i<=2*n;i++){
if(j==x[k]+1){
k++;
a[i]=1;//女生
}
else{
j++;
a[i]=2;//男生
}
}
return;
}
int main(){
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&x[i]);
pre();
memset(x,0,sizeof(x));
k=0;
for(int i=1;i<=2*n;i++){
if(a[i]==2){
k++;
x[k]=i;
}
else{
printf("%d ",(int)ceil((i-x[k])/2.0));
k--;
}
}
return 0;
}

浙公网安备 33010602011771号