题目分析:
本题的算法并不复杂,主要是要搞清楚数据的存储方式(选择一种合适的方式存储每个学生的四个成绩很重要)这里由于N的范围为10^6,故选择结构体来存放对应下标为学生的id(N只有2000的范围,所以结构体开10^6其实有点浪费空间),再者对于每个学生的每种成绩的排名我们通过下面的这种方式可以巧妙得到(而且单科成绩是会出现重复的,即并列的情况):
获取排名的方法:其实很简单,由于会出现并列单科成绩的方式,且单个学生的成绩是存储在结构体里的,通过多次排序的方式去解决这道题目是不太合适的,这里用四个数组a[],c[],m[],e[]存放每种成绩的出现的次数(因为成绩只有0~100的可能),而我们想要知道单科的成绩的排名就只需要对比该分数高的分数共有多少个+1就是该id的同学的该单科的成绩排名(这里已经回避了考虑并列的情况,十分方便!),至此我们就用num_a,num_c,num_m,num_e四个数存放了每次查询的id的四科成绩的排名,最后只要选择一个最小的,有同样最小时选择权重最高的(a > c > m > e),代码中展示了一种巧妙的判断方法,读者在下面阅读时请稍加思考
1 #include<iostream> 2 #include<string.h> 3 using namespace std; 4 5 int a[105]; 6 int c[105]; 7 int m[105]; 8 int e[105]; 9 int vis[1000000]; 10 struct Node{ 11 int A, C, M, E; 12 }k[1000000]; 13 14 int main(){ 15 int N, M; 16 while(scanf("%d%d", &N, &M) != EOF){ 17 memset(vis, 0, sizeof(vis)); 18 memset(a, 0, sizeof(a)); 19 memset(c, 0, sizeof(c)); 20 memset(m, 0, sizeof(m)); 21 memset(e, 0, sizeof(e)); 22 for(int i = 1; i <= N; i++){ 23 int id; 24 scanf("%d", &id); 25 scanf("%d%d%d", &k[id].C, &k[id].M, &k[id].E); 26 k[id].A = (k[id].C + k[id].M + k[id].E) / 3; 27 vis[id] = 1; 28 a[k[id].A]++; 29 c[k[id].C]++; 30 m[k[id].M]++; 31 e[k[id].E]++; 32 } 33 for(int i = 1; i <= M; i++){ 34 int id; 35 scanf("%d", &id); 36 if(vis[id] == 0) printf("N/A "); 37 else{ 38 //查询该id的四个成绩的排名 39 int num_a = 0; 40 int num_c = 0; 41 int num_m = 0; 42 int num_e = 0; 43 for(int j = 100; j > k[id].A; j--) num_a += a[j]; 44 for(int j = 100; j > k[id].C; j--) num_c += c[j]; 45 for(int j = 100; j > k[id].M; j--) num_m += m[j]; 46 for(int j = 100; j > k[id].E; j--) num_e += e[j]; 47 //此时得到的num是比该查询id的单一每种成绩高的个数 id的每种成绩的排名要再+1(这样的方式默认为存在并列情况) 48 //接下来要选择四个排名中最小的 如果有同样小的则按照权重a > c > m > e 49 if(num_a <= num_c && num_a <= num_m && num_a <= num_e){ 50 printf("%d A ", num_a + 1); 51 }else if(num_c <= num_m && num_c <= num_e){ 52 printf("%d C ", num_c + 1); 53 }else if(num_m <= num_e){ 54 printf("%d M ", num_m + 1); 55 }else{ 56 printf("%d E ", num_e + 1); 57 } 58 } 59 } 60 } 61 return 0; 62 }