1
题目大意:

N位考生,其准考证号00001~N。共有K道题,编号为1~ K,且每道题的分值给出。然后给出M次提交记录,
每个提交记录显示了该次提交所属考生的准考证号、交题的题号及所得的分值,其中分值要么是-1 (表示未通过编译),
要么是0到该题满分区间的一一个整数。
现在要求对所有考生按下面的规则排序:

  1. 先按K道题所得总分从高到低排序。
  2. 若总分相同,则按完美解决(即获得题目满分)的题目数量从高到低排序。
  3. 若完美解决的题目数量也相同,则按准考证号从小到大排序。
算法思路:

首先得设计好存储信息的结构,对于输入,要记录考生的id,题目编号和对于的分数,对于输出来说,需要获得考生的排名,总分,每一道题的最高得分。为此使用结构体Student保存考生的id,排名,总分,每一道题的最高得分及其是否提交情况,完美解题数和是否有编译通过的提交情况(简单理解就是是否需要输出)。然后就是对于每一条提交记录的分数的处理,处理规则如下:

  1. 对于每一条记录,记录其考生的user_idproblem_id的提交情况(students[user_id].isSubmited[problem_id] = true;)
  2. 判断该题的得分partial_score_obtained是否为-1,如果不是-1说明为通过编译的提交,将students[user_id].hasSolution置为true,表明该用户存在通过编译的提交需要输出,然后判断该分数是否比现有的得分更高,如果是则更新最高分(students[user_id].s[problem_id] = partial_score_obtained;) 并且判断该最高分是否为满分,如果是则将完美解题数加一(++students[user_id].perfect;),如果是-1不用做其他处理,因为每一道题的得分已经默认为0,无需再置为0分接下来就是初始化总分,排序,获取排名,最后输出信息即可。
排序规则:

由于存在不需要输出的考生,但是这里对所有考生都进行了排序,所以得将无需输出的人放在后面。也即是hasSolution不同的考生,根据hasSolution从高到低排序,再然后根据上述的排序规则排序。也可以采用遍历所有考生,将无需输出的考生剔除的方式来进行处理。

输出规则:

只输出hasSolutiontrue的考生,对于这些考生如果problem_id的题目isSubmited[problem_id]true,就输出分数(默认为0,对应编译不通过的情况),否则就输出"-"

提交结果:

第一次测试:测试点4错误。
第二次测试:全部正确。
截屏2020-09-29 上午8.56.01.png

注意点:
  1. hasSolution==false,表示该用户没有提交一个可通过编译的答案,不用输出该用户的信息。
  2. hasSolution==true,说明该用户至少有一个通过编译的提交,如果isSubmited[problem_id]==false说明该题没有提交输出"-",否则输出0
  3. 对于hasSolution==false的用户不参与排序。
  4. 对于测试点4考察的点主要在两个地方。第一个就是当一个用户重复提交满分代码的时候,完美解题数目不再重复记录,这里采用了在出现更高分的时候判断是否为满分在解决这个问题。第二个是当前记录的题目分数为-1,但是之前有通过编译的提交也不要进行处理,保持之前的记录即可,这里通过isSubmited数组进行的处理,无需进行记录编译出错的分数为0,因为默认分数就是0,所以只需记录通过编译的情况下的分数。
  5. 测试点4虽然考察的情况主要是以上2个情况,但是依然会出现考虑了以上2种情况依然出错的时候(比如本人(╥╯^╰╥)),这种主要是自己的代码逻辑出错,在这里记录两种情形。
出错情形一:

排序的时候将不该输出的人进行了排序,没有一道通过编译提交的人的总分为0,有通过编译的提交但是全部错误的人也是0,当前者编号较小的时候,就会获得后者本来应该有的排名。

出错情形二:

如果在一个用户的所有提交记录中,某一道题只提交了一次,并且在其提交记录中排在第一个位置,并且提交为-1,但是其他题目都是通过了编译的,那么按照本人的错误代码的写法就会导致没有通过编译的题目输出"-",而正确的输出是0,因为该用户对该题有提交。

情形二的错误代码:

if (partial_score_obtained==-1&&students[user_id].hasSolution){
    // 对于用户有其他通过编译的提交,对于本题没有通过编译,输出为0,只有没有提交记录才是 "-"
    students[user_id].isSubmited[problem_id] = true;
}
if (partial_score_obtained!=-1){
    // 说明有通过编译的提交
    students[user_id].hasSolution = true;
    students[user_id].isSubmited[problem_id] = true;
    if (partial_score_obtained>students[user_id].s[problem_id]){
        // 记录更高得分
        students[user_id].s[problem_id] = partial_score_obtained;
        // 更高得分为满分的时候完美解题数目加一
        if (partial_score_obtained==p[problem_id]){
            ++students[user_id].perfect;
        }
    }
}

错误原因isSubmited的作用是记录题目有没有提交,而错误代码的写法添加了判断条件,使其语义模糊,实属不该。

改正后的代码:
改正后的代码:
students[user_id].isSubmited[problem_id] = true;
if (partial_score_obtained!=-1){
    // 说明有通过编译的提交
    students[user_id].hasSolution = true;
    if (partial_score_obtained>students[user_id].s[problem_id]){
        // 记录更高得分
        students[user_id].s[problem_id] = partial_score_obtained;
        // 更高得分为满分的时候完美解题数目加一
        if (partial_score_obtained==p[problem_id]){
            ++students[user_id].perfect;
        }
    }
}
总结:

此题的细节处理较多,对于题目没有说清楚的点,需要通过样例数据进行推测验证,本人第一次写的时候也是各种踩坑,不过对于个人的逻辑处理能力有较大的帮助。

AC代码:
#include<cstdio>
#include<vector>
#include<unordered_map>
#include<algorithm>
#include<string>

using namespace std;

int p[6];// 每道题的满分

struct Student{
    int user_id;
    int rank; // 排名
    int total_score; // 总分
    int s[6]; // 记录每一道题的得分
    bool isSubmited[6]; // 记录题目有没有提交
    int perfect; // 完美解题数目
    bool hasSolution; // 记录是否有解决方案提交,没有的不要输出该用户信息
}students[10010];

bool cmp(Student a,Student b){
    if(a.hasSolution!=b.hasSolution){
        return a.hasSolution>b.hasSolution;
    } else if (a.total_score!=b.total_score){
        return a.total_score>b.total_score;
    } else if (a.perfect!=b.perfect){
        return a.perfect>b.perfect;
    } else {
        return a.user_id<b.user_id;
    }
}

int main(){
    int N,K,M;// 考生人数,问题数目,提交数目
    scanf("%d %d %d",&N,&K,&M);
    for (int i = 1; i <= K; ++i) {
        scanf("%d",&p[i]);
    }
    int user_id,problem_id,partial_score_obtained;
    for (int j = 0; j < M; ++j) {
        scanf("%d %d %d",&user_id,&problem_id,&partial_score_obtained);
        students[user_id].user_id = user_id;// 记录用户id
        students[user_id].isSubmited[problem_id] = true;// 记录user_id用户problem_id题目有提交
        if (partial_score_obtained!=-1){
            // 说明有通过编译的提交
            students[user_id].hasSolution = true; // 记录该用户存在可通过编译的提交,说明需要输出
            if (partial_score_obtained>students[user_id].s[problem_id]){
                // 记录更高得分
                students[user_id].s[problem_id] = partial_score_obtained;
                // 更高得分为满分的时候完美解题数目加一
                if (partial_score_obtained==p[problem_id]){
                    ++students[user_id].perfect;
                }
            }
        }
    }
    // 初始化总分
    for (int k = 1; k <= N; ++k) {
        for (int i = 1; i <= K; ++i) {
            students[k].total_score += students[k].s[i];
        }
    }
    // 排序
    sort(students+1,students+1+N,cmp);
    // 获取排名
    for (int l = 1; l <= N; ++l) {
        if (l==1){
            students[l].rank = 1;
        } else if (students[l].total_score==students[l-1].total_score){
            students[l].rank = students[l-1].rank;
        } else {
            students[l].rank = l;
        }
    }
    // 输出信息
    for (int m = 1; m <= N; ++m) {
        // 只输出需要输出的用户信息
        if (students[m].hasSolution) {
            printf("%d %05d %d", students[m].rank, students[m].user_id, students[m].total_score);
            for (int i = 1; i <= K; ++i) {
                if (!students[m].isSubmited[i]) {
                    // 该题目没有提交记录
                    printf(" -");
                } else {
                    printf(" %d", students[m].s[i]);
                }
            }
            printf("\n");
        }
    }
    return 0;
}

乔梓鑫
569 声望17 粉丝

主要分享个人学习经验和心得