排序规则:
1. 总分相同,名次相同。
2. 总分相同,按照完全正确的题目数量排序。
3. 1、2一致,根据id排名。4. 没有通过编译的,或者没有得分的,不列出。
5. 保证至少有一个人能出现在排名表上。
特别要注意的是,id的初始值问题。一开始没留心这个问题,一个测试用例过不去,纠结了好久。
id的初始值为0,意味着,它会被排在所有总分为0的学生前面!因此,id需要初始化为最大值。
想用cin读取3 * 10^5数量的数据果然还是不太科学,o(╯□╰)o,各种改动,有时能够通过,但是并不能保证一定能通过测试。
把所有的cin和cout都换成scanf和prinf,50+ms就能通过数据量最大的测试用例。有所变动的话,大概也会在30+ ~ 70+这个幅度内波动吧。
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXID = 100001;
//无法在数组中使用带参构造器,因此全局化这三个变量。
//或者不使用构造函数初始化成员变量,直接初始化。这是个人对类的执念。
int n, k, m;
struct Student {
Student():
id(MAXID),
totalScore(0),
perfectNum(0)
{
scores = new int[k + 1];
for(int i = 1; i <= k; ++i)
scores[i] = -1;
}
//重载<运算符,定义比较规则。传入sort的比较器需要是const。
bool operator<(const Student &other) const {
if(totalScore != other.totalScore) return totalScore > other.totalScore;
if(perfectNum != other.perfectNum) return perfectNum > other.perfectNum;
return id < other.id;
}
//定义输出格式。
void print() {
printf("%05d %d", id, totalScore);
for(int i = 1; i <= k; ++i)
scores[i] < 0 ? cout << " -" : cout << " " << scores[i];
cout << endl;
}
//更新总分。需要更快的话,可以把总分的更新写到main的输入循环中。
void updateTotalScore() {
for(int i = 1; i <= k; ++i)
if(scores[i] > 0) totalScore += scores[i];
}
int id;
int *scores;
int totalScore;
int perfectNum;
};
int main(void) {
cin >> n >> k >> m;
//记录每道题的总分,下标1表示第一题。
int *fullMark = new int[k + 1];
for(int i = 1; i <= k; ++i) cin >> fullMark[i];
//下标从1开始,表示一个学生。
Student *pStu = new Student[n + 1];
//作为列表名单的计时器,记录应该被列出的学生数量。
int listNum = 0;
int id, question, score;
for(int i = 0; i < m; ++i) {
scanf("%d%d%d", &id, &question, &score);
//score全为为-1的学生不被列出,因此只需要标记一下。
if(score == -1) {
if(pStu[id].scores[question] < 0) //若这个值没有被更新过(是初始值),更新为0.
pStu[id].scores[question] = 0; //标记为0,而不是-1,于是就可以直接输出了。
continue; //在这种设计下,scores[?]可以初始为任一负数。
}
//score >= 0 的情况,学生会被列出。
if(pStu[id].id == MAXID) { //新增一个需要被列出的学生。
++listNum; //更新listNum
pStu[id].id = id; //并把该“新生”的id赋值为正确的id。
}
if(score > pStu[id].scores[question]) {
//可以在这里更新总分。
pStu[id].scores[question] = score;
if(score == fullMark[question])
++pStu[id].perfectNum;
}
}
//更新总分后排序。
for(int i = 1; i <= n; ++i)
pStu[i].updateTotalScore();
sort(pStu + 1, pStu + n + 1);
//输出
int rank = 1;
int lastTotal = pStu[1].totalScore;
for(int i = 1; i <= listNum; ++i) {
//lastTotal的初始值是什么无关紧要,总可以在这里赋上正确值。
if(pStu[i].totalScore < lastTotal) {
rank = i;
lastTotal = pStu[i].totalScore;
}
cout << rank << " ";
pStu[i].print();
}
//虽然用固定数组操作起来方便点,但我总是喜欢使用动态数组。o(╯□╰)o
delete[] fullMark;
delete[] pStu;
return 0;
}