前言
这题是我大一就做过的,奈何自己当时水平太低结果当时就只拿了10分;现在大三20minAC,感觉还是有点进步的哈哈哈…
题目链接地址:P1068 [NOIP2009 普及组] 分数线划定
解题思路:
题目初看一大串文字表述很复杂,其实并不复杂。这道题要做的人物就是先把n个志愿者的成绩按照它已经指定好的方式排序,然后将录取人数*1.5利用向下取整(对应在C语言里是直接进行强制类型转换),在排好序的数组上找相应位置那个志愿者的分,然后看是否有同分情况有就顺延然后确定正式进入面试的人数,然后再按照被确定入围的面试者在数组对应的位置依次从大到小输出相应报名号和他的成绩即可。
因此,预排序成为了一个必不可少的动作,但是这里的预排序和普通题目下的预排序不同之处在于这里比较的指标除了分数之外还有报名号。因此,在利用相应排序模板的时候,一定要注意,例如,我使用的归并排序,将相等的情况单独处理。归并排序设计到一个分治法的思想,当在进行最小归并的时候当分数相等的时候要注意按照报名号进行有限归入数组的操作;这样递归返回的时候可以保证局部顺序的正确性从而保证全局的正确性。
因为本题属于多依据的排序,所以对于数组元素,在C语言里还是用结构体来存储比较方便。最后还是给出我的AC代码:
#include <stdio.h>
#include <stdlib.h>
struct node{
int No;
int score;
};
void Merge(int left,int mid,int right,struct node a[],struct node b[]){
int i,j,k;
for(i=left;i<=right;i++)
b[i]=a[i];
i=left;
j=mid+1;
k=left;
while(i<=mid&&j<=right){
if(b[i].score>b[j].score){
a[k]=b[i];
k++;
i++;
}else if(b[j].score>b[i].score){
a[k]=b[j];
k++;
j++;
}else{
if(b[i].No<b[j].No){
a[k]=b[i];
k++;
i++;
}else{
a[k]=b[j];
k++;
j++;
}
}
}
while(i<=mid){
a[k]=b[i];
i++;
k++;
}
while(j<=right){
a[k]=b[j];
k++;
j++;
}
return;
}
void Mergesort(int left,int right,struct node a[],struct node b[]){
if(left>=right)
return;
int mid=(left+right)/2;
Mergesort(left,mid,a,b);
Mergesort(mid+1,right,a,b);
Merge(left,mid,right,a,b);
return;
}
int main(int argc, char *argv[]) {
int n,m,i,ceil;
scanf("%d%d",&n,&m);
ceil=(int)(1.5*m);
struct node racer[n],b[n];
for(i=0;i<n;i++)
scanf("%d%d",&racer[i].No,&racer[i].score);
Mergesort(0,n-1,racer,b);
printf("%d ",racer[ceil-1].score);
while(1){
if(racer[ceil-1].score==racer[ceil].score)
ceil++;
else
break;
}
printf("%d\n",ceil);
for(i=0;i<ceil;i++){
printf("%d %d\n",racer[i].No,racer[i].score);
}
return 0;
}