题目来源:QZEZOJ
题目传送门
题目描述
晚会上有好多小伙伴,准备开始一场舞蹈。
舞蹈是2 个人一起跳的,而且是一男一女。
规定所有的人都站成了一排跳舞。
这一排人的顺序满足两点:
①对于任何一对舞伴,男生一定在女生的左边方向。
②任何一对舞伴之间,要么没有人,要么就有若干对舞伴。
其中女生知道自己左边有几个男生。
现在就请你再告诉这些女生,她们的舞伴距离她们多远(指包括那个男生,一共有多少男生夹在这对舞伴之间)。
输入
第一行为一个数N,表示参与的女生个数。
第二行
N
N
N 个数,第i个数为
A
i
A_i
Ai,表示从左往右数的第
i
i
i个女生左边共有
A
i
A_i
Ai个男生;
输出
输出共一行 N N N个数,每两个整数之间用一个空格隔开,行末无空格。表示 N N N 个女生与其舞伴的距离。
样例输入
6
4 5 6 6 6 6
样例输出
1 1 1 4 5 6
提示
对于
30
%
30\%
30%的数据:
1
≤
N
≤
50
1≤N≤50
1≤N≤50;
对于
50
%
50\%
50%的数据:
1
≤
N
≤
2
,
000
1≤N≤2,000
1≤N≤2,000;
对于
100
%
100\%
100%的数据:
1
≤
N
≤
500
,
000
1≤N≤500,000
1≤N≤500,000;
1
≤
A
i
≤
A
j
≤
N
1≤A_i≤A_j≤N
1≤Ai≤Aj≤N(
1
≤
i
<
j
≤
N
1≤i<j≤N
1≤i<j≤N);数据保证合法,不必验错。
题目解析
先来看一看样例解释:
这里菱形表示的是男生,三角形表示的是女生,一组舞伴用一条曲线连起来,这样答案就很显然了。
预处理
我们看一看输入的是什么:
第二行 N N N个数,第i个数为 A i A_i Ai,表示从左往右数的第 i i i个女生左边共有 A i A_i Ai个男生;
输入的数不方便操作,我们就可以把它转化成类似于上图的样子。
这里将输入的数组
x
x
x转化为数组
a
a
a.
我们用变量
k
k
k来统计左端男生的个数,如果到达一定数量了,就放一个女生就可以了。这里用
1
1
1来表示女生,
2
2
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
≤
500
,
000
n \leq 500,000
n≤500,000 ,比较大,
O
(
N
2
)
O\left( N^2\right)
O(N2)会炸掉,不能等出现女生在开始找,所以,我们可以用空间换时间,开一个栈,记录下男生的位置就可以了。这样可以实现
O
(
N
)
O\left(N \right)
O(N)的复杂度了。
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;
}