我的PAT-ADVANCED代码仓:https://github.com/617076674/PAT-ADVANCED
我的Data Structures and Algorithms代码仓:https://github.com/617076674/Data-Structures-and-Algorithms
原题链接:
PAT-ADVANCED1075:https://pintia.cn/problem-sets/994805342720868352/problems/994805393241260032
Data Structures and Algorithms7-15:https://pintia.cn/problem-sets/16/problems/677
题目描述:
PAT-ADVANCED1075、Data Structures and Algorithms7-15:
题目翻译:
1075 PAT判题系统
状态列表显示了每次提交的分数,PAT的排名就是根据这个状态列表生成的。现在你需要生成PAT的排名。
输入格式:
每个输入文件包含一个测试用例。对每个测试用例,第一行包含3个正整数,N(<= 10 ^ 4),代表用户总数,K(<= 5)代表题目总数,以及M(<= 10 ^ 5),代表提交总数。假设用户的编号是一个5位数,且在00001 ~ N的范围内,问题编号在1 ~ K的范围内。接下来的1行包含K个正整数p[i](i = 1, ..., K),其中p[i]代表第i个问题的满分值。接下来的M行,每行以下述形式给出一次提交的信息:
user_id problem_id partial_score_obtained
如果编译失败,则partial_score_obtained是-1。如果编译通过,则partial_score_obtained是一个[0, p[problem_id]]之间的值。一行中的所有数字由一个空格隔开。
输出格式:
对每个测试用例,你需要按下述形式输出排名列表:
rank user_id total_score s[1] ... s[K]
排名rank是根据total_score由大到小的顺序生成的,拥有相同total_score的用户的排名相同。s[i]是i号问题的得分。如果某个用户没有对某问题没有进行过任何提交,则在相应位置输出“-”。如果某用户对同个问题有多次提交,则输出最高分数。
排名列表必须根据rank的非降序排列。对有相同排名的用户,必须根据全对题数进行非升序排列。如果rank和全对题数均相同,则根据id的増序排列。对于那些从来没有提交过能编译成功的用户,以及那些从来没有提交过任何解决方案的用户,他们不应该出现的排名列表中。题目保证在排名列表中至少有一个用户能被输出。
输入样例:
7 4 20
20 25 25 30
00002 2 12
00007 4 17
00005 1 19
00007 2 25
00005 1 20
00002 2 2
00005 1 15
00001 1 18
00004 3 25
00002 2 25
00005 3 22
00006 4 -1
00001 2 18
00002 1 20
00004 1 15
00002 4 18
00001 3 4
00001 4 2
00005 2 -1
00004 2 0
输出样例:
1 00002 63 20 25 - 18
2 00005 42 20 0 22 -
2 00007 42 - 25 - 17
2 00001 42 18 18 4 2
5 00004 40 15 0 25 -
知识点:排序
思路:先筛选出需要显示的用户,再对需要显示的用户进行排名
构建一个结构体scoreConsist来保存用户id信息,用户排名信息,用户的总分、各题分数、全对题数。其中结构体中存储分数的数组int score[7]需要初始化为-2,以和编译失败的-1和编译成功但得分为0的情况相区分。
再定义一个数组scoreConsist scores[10001],scores[i]保存编号为i的用户的得分信息。为什么用数组呢?因为我们在多次提交中取的是得分的最大值,对于某次输入,把用户id当作数组的下标能用O(1)的时间复杂度定位到该用户id原有的分数。
既然数组的下标已经代表了用户的id,那为什么结构体scoreConsist中还需要保存用户id信息呢?
因为排序之后数组的下标就不再和用户id值相对应了。
为什么要强调先筛选出需要显示的用户,再对需要显示的用户进行排名呢?
因为我的排名的生成过程时根据该用户在vector<scoreConsist> scoreConsists的索引来生成的,如果在遍历vector<scoreConsist> scoreConsists时有需要跳过不显示的用户,那么排名编号就会出错。一开始我就是犯了这个错误,导致测试点4无法通过。
注意看样例00005编号的第2题,编译失败所以显示得分0。而00004编号的第2题虽然编译成功,但得分是0所以显示0。
根据题意,只有那些从来没有提交过能编译成功的用户,以及那些从来没有提交过任何解决方案的用户,才不包含在排名列表中。对于有过提交且编译通过的用户,可能其得分是0,其总得分也是0,但应该将这些用户包含在排名列表中。
时间复杂度是O(NlogN)。空间复杂度是O(N)。
C++代码:
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
/*
scoreConsist用于存储一个人的得分情况
*/
struct scoreConsist {
int id;
int rank;
//score[0]存储总分,score[1] ~ score[K]存储各题分数,score[K + 1]存储全对题数
//初始化值全为-2,和编译失败结果-1,编译通过但得分为0相区别开
int score[7] = {-2, -2, -2, -2, -2, -2, -2};
};
int N, K, M;
scoreConsist scores[10001]; //scores[i]存储第i号人的得分情况
bool cmp(scoreConsist s1, scoreConsist s2);
int main() {
cin >> N >> K >> M;
int problems[K + 1]; //存储各题满分值
for(int i = 1; i <= K; i++) {
cin >> problems[i];
}
int user_id, problem_id, partial_score_obtained;
for(int i = 0; i < M; i++) {
cin >> user_id >> problem_id >> partial_score_obtained;
scores[user_id].id = user_id;
if(partial_score_obtained > scores[user_id].score[problem_id]) {
scores[user_id].score[problem_id] = partial_score_obtained;
}
}
for(int i = 1; i <= N; i++) {
int sum = 0;
int perfect = 0;
for(int j = 1; j <= K; j++) {
if(scores[i].score[j] == -1 || scores[i].score[j] == -2) {
continue;
}
sum += scores[i].score[j];
if(scores[i].score[j] == problems[j]) {
perfect++;
}
}
scores[i].score[0] = sum; //计算总分
scores[i].score[K + 1] = perfect; //计算全对题数
}
vector<scoreConsist> scoreConsists;
for(int i = 1; i <= N; i++) {
bool flag = false;
for(int j = 1; j <= K; j++) {
if(scores[i].score[j] != -2 && scores[i].score[j] != -1) {
flag = true;
break;
}
}
if(!flag) {
continue;
}
scoreConsists.push_back(scores[i]); //滤除去不需要显示的数据
}
sort(scoreConsists.begin(), scoreConsists.end(), cmp); //对需要显示的数据进行题目要求的排序
for(int i = 0; i < scoreConsists.size(); i++) {
scoreConsists[i].rank = i + 1;
if(i > 1 && scoreConsists[i].score[0] == scoreConsists[i - 1].score[0]) {
scoreConsists[i].rank = scoreConsists[i - 1].rank;
}
printf("%d %05d %d ", scoreConsists[i].rank, scoreConsists[i].id, scoreConsists[i].score[0]);
for(int j = 1; j <= K; j++) {
if(scoreConsists[i].score[j] == -2) { //如果是-2,说明根本没有提交,显示“-”
printf("-");
} else if(scoreConsists[i].score[j] == -1) { //如果是-1,说明提交了但是编译失败,根据样例应该显示“0”
printf("0");
} else {
printf("%d", scoreConsists[i].score[j]);
}
if(j != K) {
printf(" ");
} else {
printf("\n");
}
}
}
}
bool cmp(scoreConsist s1, scoreConsist s2) {
if(s1.score[0] == s2.score[0]) {
if(s1.score[K + 1] == s2.score[K + 1]) {
return s1.id < s2.id;
} else {
return s1.score[K + 1] > s2.score[K + 1];
}
} else {
return s1.score[0] > s2.score[0];
}
}
C++解题报告: