题目描述
教室的墙上挂满了气球,五颜六色,小朋友们非常喜欢。
刚一下课,小朋友们就打算去抢这些气球。每个气球在墙上都有一定的高度,只有当小朋友跳起来时,手能够到的高度大于等于气球的高度,小朋友才能摘到这个气球。为了公平起见,老师让跳的低的小朋友先摘,跳的高的小朋友后摘。小朋友都很贪心,每个小朋友在摘气球的时候都会把自己能摘的气球都摘掉。
很巧的是,小朋友们跳起来手能够着的高度都不一样,这样就不会有跳起来后高度相同的小朋友之间发生争执了。
输入
第一行输入两个空格分隔的整数 n,m(1≤n,m≤100000) ,其中 n 表示小朋友的数量,m 表示墙上气球的数量。
第二行输入 n 个正整数(每两个整数之间用空格隔开),第 i 个数为 ai(1≤ai≤109),表示第 i 个小朋友跳起来手能够着的高度为 ai 。
第三行输入 m 个正整数(每两个整数之间用空格隔开),第 i 个数为hi ,表示第 i 个气球的高度为 hi。
输出
输出一共 n 行,每行一个整数。 第i 行表示第 i 个小朋友摘到的气球数量。
样例输入
5 6
3 7 9 6 4
1 2 3 4 5 6
样例输出
3
0
0
2
1
解决方案
#include <stdio.h>
#define swap(a,b){__typeof(a) __tmp=a;a=b;b=__tmp;}
//利用归并排索引
void merge(int *nums,int start,int end,int * ans){
if(start>=end) return;
int mid=(start+end)>>1;
merge(nums,start,mid,ans);
merge(nums,mid+1,end,ans);
int i=start,j=mid+1,k=0;
int * tmp=(int *)malloc(sizeof(int)*(end-start+1));
while(i<=mid||j<=end){
if(j>end||i<=mid && nums[ans[i]]<=nums[ans[j]]){
tmp[k++]=ans[i++];
}else{
tmp[k++]=ans[j++];
}
}
memcpy(ans+start,tmp,sizeof(int)*k);
free(tmp);
}
//利用快排得到气球高度
void quick_sort(int *nums,int start,int end){
if(start>=end) return;
int i=start,j=end,mid=nums[(start+end)>>1];
while(i<=j){
while(i<=j&&nums[i]<mid) i++;
while(i<=j&&nums[j]>mid) j--;
if(i<=j){
swap(nums[i],nums[j]);
i++;j--;
}
}
quick_sort(nums,start,j);
quick_sort(nums,i,end);
}
//二分查找右边界,找到第一个大于val的值
int bin_serach(int *nums,int size,int val){
int left=0,right=size;
while(left<right){
int mid=(left+right)>>1;
if(nums[mid]<=val) left=mid+1;
else right=mid;
}
return left;
}
// 以以下数据为例
//3 7 9 6 4
//1 2 3 4 5 6
int main(){
int m,n;
scanf("%d%d",&m,&n);
int * arr1=(int *)malloc(sizeof(int)*m); //存储孩子能够到的最大高度 3 7 9 6 4
int * arr1_idx=(int *)malloc(sizeof(int)*m); //存储arr1排序后的索引 0 4 3 1 2
int * ans=(int *)malloc(sizeof(int)*m); //存储最终结果
memset(ans,0,sizeof(int)*m);
for(int i=0;i<m;i++){
scanf("%d",&arr1[i]);
arr1_idx[i]=i;
}
int * arr2=(int *)malloc(sizeof(int)*n); //存储气球高度 1 2 3 4 5 6
for(int i=0;i<n;i++){
scanf("%d",&arr2[i]);
}
//从小到大排序
merge(arr1,0,m-1,arr1_idx);
quick_sort(arr2,0,n-1);
//存储前面的值,比如第一次:0号孩子能够到的高度为3,它在arr2的左边界为3(arr1[arr1_idx[0]]),第二个孩子能够到的高度为4,左边界为4,他能摘的气球需要减去前面的3,即为1;
int sum=0;
for(int i=0;i<m;i++){
if(sum==n) break;//当前面孩子摘满了,后面无需在判断,直接为默认的0即可;
int val=arr1[arr1_idx[i]]; //arr1从小到大排序,需要寻找的值
int idx=bin_serach(arr2,n,val); // 到第一个大于val的值的索引
ans[arr1_idx[i]]=idx-sum;
sum+=ans[arr1_idx[i]];
}
for(int i=0;i<m;i++){
printf("%d\n",ans[i]);
}
//释放malloc申请的空间
free(arr1);
free(arr1_idx);
free(arr2);
free(ans);
return 0;
}
小结
关键在于排索引,数据规模较大时,考虑快排或者归并,快排可能改变两个相等量的相对顺序(不稳定),归并则不会