您的位置:首页 > 其它

蓝桥杯 小朋友排队

2016-03-18 18:23 260 查看
题目链接:点击打开链接

解题思路:

首先,每位小朋友的最少交换次数:其左边比他高的小朋友数量+右边比他矮的小朋友数量;

如果直接对每位小朋友求:左边比他高+右边比他矮,时间复杂度为n^2(n<100000)-----------会超时。。

做法:

1、记录下每个小朋友的身高和原始位置;

2、将小朋友按身高排序;

3、{

3.1 按身高的顺序将小朋友逐个还原到原始位置(update());

3.2 对每个还原的小朋友,查询其左右两边已有的小朋友数量记为tl tr(可以知道,先插入的小朋友身
高较矮);

3.3 对当前小朋友(第i个)而言,它将被调换位置:(i-tl-1)+(tr);//左边有i-1个位置,已经插入tl
位(比他矮),则有(i-1-tl)位比他高的小朋友会和他交换位置;

3.4 更新ans;

}

注意,:代码中的ans、l、r的数据类型设为long long

再有,这题的数据操作比较简单因此对树状数组可以不设add,更新和查询的函数可以适当写的简单点

<span style="font-size:18px;">//小朋友排队
#include<stdio.h>
#include<algorithm>
#define N 100005
struct node{
int h,no;
}H
;
struct treeNode{
int sum,left,right;
}tree[N*4];

int n;
bool cmp1(const node x,const node y){//按高度排
if(x.h!=y.h) return x.h<y.h;
else return x.no<y.no;
}
void build(int s,int l,int r){
tree[s].left=l;
tree[s].right=r;
if(l==r){
//tree[s].sum=1;
return ;
}
int mid=(l+r)/2;
build(s*2,l,mid);
build(s*2+1,mid+1,r);
//tree[s].sum=tree[s*2].sum+tree[s*2+1].sum;
}
void update(int s,int l,int r){
if(tree[s].left==l&&tree[s].right==r){
tree[s].sum=1;
return;
}
int mid=(tree[s].left+tree[s].right)/2;
if(r<=mid)
update(s*2,l,r);
else
update(s*2+1,l,r);
tree[s].sum=tree[s*2].sum+tree[s*2+1].sum;
}
int query(int s,int l,int r){
if(l>r) return 0;
if(tree[s].left==l&&tree[s].right==r){
return tree[s].sum;
}
int mid=(tree[s].left+tree[s].right)/2;
if(r<=mid)
return query(s*2,l,r);
else if(mid<l)
return query(s*2+1,l,r);
else
return query(s*2,l,mid)+query(s*2+1,mid+1,r);

}
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&H[i].h);
H[i].no=i;
}
std::sort(H,H+n,cmp1);//按高度排
//printf("%d %d",H[0].h,H[n-1].h);
build(1,0,n-1);
long long ans=0;
long long l,r;
for(int i=0;i<n;i++){//按高度顺序插入
update(1,H[i].no,H[i].no);
l=H[i].no-query(1,0,H[i].no-1);//左边l个比H[i]高,即交换l次
r=query(1,H[i].no+1,n-1);//右边r个比H[i]矮,即交换r次

ans += (1+l+r)*(l+r)/2;//l,r 必须定义为 long long 否则l=99999 r=0 WA
}
printf("%lld\n",ans);
return 0;
}
</span>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  蓝桥杯