题目大意:给出N名考生的提交记录,总共有K道题,M条提交记录,要求按照总分降序、全对题目数量降序、考生id升序的方式进行排名,并输出每位考生每道题的得分。但是有一些额外要求:① 记录中得分如果是 -1,说明提交没有通过编译。② 没有任何题目通过编译的考生(也即没有得分大于-1的题目的考生),不输出。③ 输出的考生如果有题目得分是-1,应该输出0。④ 同一道题提交多次的,取最高分。⑤ 输出的考生如果有题目没有提交记录(即没有任何得分),应该输出 “-”。
还是一贯的阅读理解题,由于题目的得分可以是-1及以上的值,每道题的初始成绩应当设置为-2。之后,输入的过程中,如果有得分大于-1的,说明该名考生需要输出。如果得分大于-1,判断是否需要更新该题得分,以及是否是满分。如果得分是-1,那么记录-1分。
但这样做有两个坑点(测试点4):
① 满分重复提交。所以对于该考生全对题目数量是否要+1需要先判断该题是否曾经得过满分了。
② 前面提交问题K有得分,但是之后又提交了一次-1分。所以对于分数是-1的情形,需要先判断该题是否曾经有得分,然后再决定是否要更新。
但是这两个坑点可以用一个很简单的方法一起避免,就是只有当输入的分数大于该题已经得到的分数时,才进入是否要更新分数的判断,否则直接忽略。如下:
for (int i = 0; i < M; ++i)
{
int id, problem, score;
scanf("%d%d%d", &id, &problem, &score);
if(score > allUsers[id].score[problem])
{
if(score > -1)
{
allUsers[id].id = id;
allUsers[id].hasSolution = true;
allUsers[id].score[problem] = max(score, allUsers[id].score[problem]);
if(score == fullScore[problem]) allUsers[id].perfectNum++;
}
else if(score == -1) allUsers[id].score[problem] = -1;
}
}
否则就要加两条判断:
for (int i = 0; i < M; ++i)
{
int id, problem, score;
scanf("%d%d%d", &id, &problem, &score);
if(score > -1)
{
allUsers[id].id = id;
allUsers[id].hasSolution = true;
if(score == fullScore[problem] && allUsers[id].score[problem] < score) allUsers[id].perfectNum++;
allUsers[id].score[problem] = max(score, allUsers[id].score[problem]);
}
else if(score == -1 && allUsers[id].score[problem] == -2) allUsers[id].score[problem] = -1;
}
AC代码:
#include <vector>
#include <algorithm>
#include <cstdio>
using namespace std;
struct user
{
int id;
int score[6];
int totalScore;
int rank;
int perfectNum;
bool hasSolution;
user():totalScore(0), perfectNum(0), hasSolution(false)
{
fill(score, score + 6, -2);
}
bool operator<(const user &other)
{
if(this->totalScore != other.totalScore) return this->totalScore > other.totalScore;
else if(this->perfectNum != other.perfectNum) return this->perfectNum > other.perfectNum;
else return this->id < other.id;
}
}allUsers[10010];
int main()
{
int N, K, M;
scanf("%d%d%d", &N, &K, &M);
vector<int> fullScore(K+1);
for (int i = 1; i <= K; ++i)
scanf("%d", &fullScore[i]);
for (int i = 0; i < M; ++i)
{
int id, problem, score;
scanf("%d%d%d", &id, &problem, &score);
if(score > -1)
{
allUsers[id].id = id;
allUsers[id].hasSolution = true;
if(score == fullScore[problem] && allUsers[id].score[problem] < score) allUsers[id].perfectNum++;
allUsers[id].score[problem] = max(score, allUsers[id].score[problem]);
}
else if(score == -1 && allUsers[id].score[problem] == -2) allUsers[id].score[problem] = -1;
}
vector<user> v;
for (int i = 1; i <= N; ++i)
{
if(allUsers[i].hasSolution)
{
for (int j = 1; j <= K; ++j)
allUsers[i].totalScore += max(0, allUsers[i].score[j]);
v.push_back(allUsers[i]);
}
}
sort(v.begin(), v.end());
int rank = 1;
v[0].rank = rank++;
printf("%d %05d %d",v[0].rank, v[0].id, v[0].totalScore);
for (int i = 1; i <= K; ++i)
{
if(v[0].score[i] > -2) printf(" %d", max(0, v[0].score[i]));
else printf(" -");
if(i == K) printf("\n");
}
for (int i = 1; i < v.size(); ++i)
{
if(v[i].totalScore == v[i-1].totalScore) v[i].rank = v[i-1].rank;
else v[i].rank = rank;
rank++;
printf("%d %05d %d",v[i].rank, v[i].id, v[i].totalScore);
for (int j = 1; j <= K; ++j)
{
if(v[i].score[j] > -2) printf(" %d", max(0, v[i].score[j]));
else printf(" -");
if(j == K) printf("\n");
}
}
return 0;
}
优化一点的代码,遍历次数多了点,但是思路很自然:先读入所有数据,每次更新分数为已读入的最大值,并确定哪些人可以被输出(至少有一个分数大于-1)。之后,对于这些可以被输出的人,再统计他们的总分以及满分个数。最后排名。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 10010;
struct user
{
int id;
vector<int> score;
int totalScore;
int perfectCnt;
int rank;
bool printOut;
user():totalScore(0), perfectCnt(0), printOut(false){};
bool operator <(const user& other)
{
if(this->totalScore != other.totalScore) return this->totalScore > other.totalScore;
else if(this->perfectCnt != other.perfectCnt) return this->perfectCnt > other.perfectCnt;
else return this->id < other.id;
}
}allUsers[MAXN];
int main()
{
int N, K, M;
scanf("%d%d%d", &N, &K, &M);
vector<int> fullScore(K+1, 0);
for (int i = 1; i <= K; ++i)
{
scanf("%d", &fullScore[i]);
}
for (int i = 1; i <= N; ++i)
{
allUsers[i].score = vector<int>(K+1, -2);
}
for (int i = 0; i < M; ++i)
{
int id, problem, score;
scanf("%d%d%d", &id, &problem, &score);
allUsers[id].id = id;
allUsers[id].score[problem] = max(allUsers[id].score[problem], score);
if(score > -1) allUsers[id].printOut = true;
}
vector<user> rankList;
for (int i = 1; i <= N; ++i)
{
if(allUsers[i].printOut)
{
for (int j = 1; j <= K; ++j)
{
allUsers[i].totalScore += max(0,allUsers[i].score[j]);
allUsers[i].perfectCnt += allUsers[i].score[j] == fullScore[j] ? 1 : 0;
}
rankList.push_back(allUsers[i]);
}
}
sort(rankList.begin(), rankList.end());
int rank = 1;
rankList[0].rank = rank++;
for (int i = 1; i < rankList.size(); ++i)
{
if(rankList[i].totalScore == rankList[i-1].totalScore) rankList[i].rank = rankList[i-1].rank;
else rankList[i].rank = rank;
rank++;
}
for (int i = 0; i < rankList.size(); ++i)
{
printf("%d %05d %d", rankList[i].rank, rankList[i].id, rankList[i].totalScore);
for (int j = 1; j <= K; ++j)
{
if(rankList[i].score[j] > -2) printf(" %d", max(0, rankList[i].score[j]));
else printf(" -");
}
printf("\n");
}
return 0;
}