晚会舞蹈 题解

题目来源: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 1N50
对于 50 % 50\% 50%的数据: 1 ≤ N ≤ 2 , 000 1≤N≤2,000 1N2,000
对于 100 % 100\% 100%的数据: 1 ≤ N ≤ 500 , 000 1≤N≤500,000 1N500,000 1 ≤ A i ≤ A j ≤ N 1≤A_i≤A_j≤N 1AiAjN 1 ≤ i < j ≤ N 1≤i<j≤N 1i<jN);数据保证合法,不必验错。

题目解析

先来看一看样例解释:
在这里插入图片描述
这里菱形表示的是男生,三角形表示的是女生,一组舞伴用一条曲线连起来,这样答案就很显然了。

预处理

我们看一看输入的是什么:

第二行 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 n500,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;
}

完结撒花

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值