#include <iostream>
#include <string>
#include <algorithm>
#include <unordered_map>
#include <vector>
#include <set>
#include <iomanip>
using namespace std;
const double eps = 1e-5;
const int N = 1e5 + 5;
int oper, rk[405], cnt;
unordered_map<long long, bool> SID;
unordered_map<string, int> ID;
string cname[4] = {"Chinese", "Mathematics", "English", "Programming"};
int name2id(string name) // 给一个字符串名字,得到它对应的名字id
{
if (!ID.count(name))
ID[name] = ++cnt;
return ID[name];
}
long long to_num(string s) // 给出字符串形式的sid,然后转成long long类型的sid
{
int res = 0;
for (int i = 0; i < s.size(); i++)
res = res * 10 + s[i] - '0';
return res;
}
string ll2str(long long sid)
{
string res = "";
int t = 0, r;
while (sid)
r = sid % 10, sid /= 10, res += (r + '0');
while (res.size() < 10)
res += '0';
reverse(res.begin(), res.end());
return res;
}
class Student
{
public:
long long sid;
int cid;
string name;
int k[4], total;
double avg;
void create(long long sid, int cid, string name, int k1, int k2, int k3, int k4)
{
this->sid = sid, this->cid = cid, this->name = name;
this->k[0] = k1, this->k[1] = k2, this->k[2] = k3, this->k[3] = k4;
total = k1 + k2 + k3 + k4, avg = 0.25 * (k1 + k2 + k3 + k4) + eps;
}
int get_rank() // 对于一个学生,求它的排名
{
int p = 1, tmp = 0;
for (int i = 400; i > total; i--)
{
if (rk[i])
tmp += rk[i]; // 并列的加一起
else
p += tmp, tmp = 0;
}
return p + tmp;
}
};
unordered_map<long long, Student> Stu; // 通过sid快速获取对应的学生对象
vector<Student> sname[N], stu; // sname是通过字符串name转化得到的id对应的重名学生,stu是总学生
class course
{
public:
double avg = 0, tot = 0; // 科目的平均分,总分
int passed = 0, unpassed = 0; // 通过人数,不过人数
};
class Room
{
public:
vector<Student> stu; // 班级对应的学生集合
course kemu[4]; // 四个科目对应的信息
int pass[5] = {0, 0, 0, 0, 0}; // 通过0,1,2,3,4,科的人数,后缀和计算
} room[21], sum_room; // 前面是各个班级,后面是所有班级(可以优化成room【0】,但是懒得弄了)
void add_oper()
{
long long sid;
int cid, k1, k2, k3, k4, id;
string name;
while (true)
{
printf("Please enter the SID, CID, name and four scores. Enter 0 to finish.\n");
cin >> sid;
if (!sid)
return;
cin >> cid >> name >> k1 >> k2 >> k3 >> k4;
if (SID[sid])
cout << "Duplicated SID.\n";
else
{
SID[sid] = true, id = name2id(name);
Student now;
now.create(sid, cid, name, k1, k2, k3, k4);
sname[id].push_back(now), stu.push_back(now); // 为名字对应的集合sname添加,总集合stu添加
room[cid].stu.push_back(now), Stu[sid] = now; // 为cid班级的学生集合添加,建立sid与Student映射
rk[now.total]++;
}
}
}
void remove_oper() // 删除学生信息
{
long long sid;
string name;
int id, sum; // sum记录一共删除了几个
while (true)
{
printf("Please enter SID or name. Enter 0 to finish.\n"), sum = 0;
cin >> name;
if (name[0] >= '0' && name[0] <= '9') // 判断是sid还是name
{
sid = to_num(name); // 转为正常的long long类型的sid,方便建立映射
if (!sid)
return;
else if (SID[sid])
SID[sid] = false, sum++, rk[Stu[sid].total]--; // 标记false意味着删除了
}
else
{
id = name2id(name); // 通过name获得名字id,然后访问名字id对应的学生集合
for (int i = 0; i < sname[id].size(); i++)
if (SID[sname[id][i].sid]) // 对该集合没被删除的学生标记false并统计删除人数
SID[sname[id][i].sid] = false, rk[Stu[sname[id][i].sid].total]--, sum++;
}
printf("%d student(s) removed.\n", sum);
}
}
void select_oper() // 查询学生
{
long long sid;
string name;
int id;
while (true)
{
printf("Please enter SID or name. Enter 0 to finish.\n");
cin >> name;
if (name[0] >= '0' && name[0] <= '9')
{
sid = to_num(name);
if (!sid)
return;
if (SID[sid])
{
Student now = Stu[sid];
cout << now.get_rank() << " " << ll2str(now.sid) << " " << now.cid << " " << now.name << " ";
cout << now.k[0] << " " << now.k[1] << " " << now.k[2] << " " << now.k[3] << " ";
cout << now.total, printf(" %.2lf\n", now.avg);
}
}
else
{
unordered_map<int, bool> st;
id = name2id(name);
vector<pair<int, long long>> tmp;
for (int i = 0; i < sname[id].size(); i++)
if (SID[sname[id][i].sid] && !st[sname[id][i].sid]) // 记录所有没被删除的学生排名和sid
sid = sname[id][i].sid, st[sid] = true, tmp.push_back({Stu[sid].get_rank(), sid});
for (auto t : tmp)
{
Student now = Stu[t.second]; // 通过sid直接访问Stu的学生映射
cout << t.first << " " << ll2str(now.sid) << " " << now.cid << " ", cout << now.name << " ";
cout << now.k[0] << " " << now.k[1] << " " << now.k[2] << " " << now.k[3] << " ";
cout << now.total, printf(" %.2f\n", now.avg);
}
}
}
}
void show_score(Room r, vector<Student> &stu) // 计算并显示各科信息,输入班级和班级对应的学生集合
{
unordered_map<int, bool> st;
int sum = 0, tot_pass = 0; // tot_pass记录一个人一共通过了几科,用于记录pass数据
for (int i = 0; i < 4; i++) // 重置
r.kemu[i].avg = 0.0, r.kemu[i].passed = 0, r.kemu[i].unpassed = 0, r.kemu[i].tot = 0.0;
for (int i = 0; i < 5; i++)
r.pass[i] = 0;
if (stu.size())
{
for (int i = 0; i < stu.size(); i++)
if (SID[stu[i].sid] && !st[stu[i].sid])
{
st[stu[i].sid] = true, tot_pass = 0, sum++; // sum代表这个班级的人数加一,tot_pass重置,意味着开始记录这个人的通过科目数
for (int j = 0; j < 4; j++)
{
r.kemu[j].tot += stu[i].k[j]; // 总分用于配合sum计算平均分
if (stu[i].k[j] >= 60)
r.kemu[j].passed++, tot_pass++;
else
r.kemu[j].unpassed++;
}
r.pass[tot_pass]++; // 这个人通过了tot_pass科
}
for (int i = 0; i < 4; i++) // 计算科平均分
r.kemu[i].avg = (r.kemu[i].tot / sum) + eps;
for (int i = 4; i > 1; i--) // 后缀和计算pass科目,注意0代表通过了0科,而不是至少通过了0科,所以不跟后面加和
r.pass[i - 1] += r.pass[i];
}
for (int i = 0; i < 4; i++) // 输出四科信息
{
course c = r.kemu[i];
cout << cname[i] << "\n";
printf("Average Score: ");
cout << fixed << setprecision(2) << c.avg << "\n";
printf("Number of passed students: %d\n", c.passed);
printf("Number of failed students: %d\n\n", c.unpassed);
}
printf("Overall:\n"); // 输出通过信息
printf("Number of students who passed all subjects: %d\n", r.pass[4]);
printf("Number of students who passed 3 or more subjects: %d\n", r.pass[3]);
printf("Number of students who passed 2 or more subjects: %d\n", r.pass[2]);
printf("Number of students who passed 1 or more subjects: %d\n", r.pass[1]);
printf("Number of students who failed all subjects: %d\n\n", r.pass[0]);
}
void score_oper()
{
int id;
printf("Please enter class ID, 0 for the whole statistics.\n");
cin >> id; // 这里本来可以优化一下,让room【0】作为所有班级的总和
if (!id)
show_score(sum_room, stu);
else
show_score(room[id], room[id].stu);
}
void show_cd() // 菜单
{
printf("Welcome to Student Performance Management System (SPMS).\n\n");
printf("1 - Add\n");
printf("2 - Remove\n");
printf("3 - Query\n");
printf("4 - Show ranking\n");
printf("5 - Show Statistics\n");
printf("0 - Exit\n\n");
cin >> oper;
switch (oper)
{
case 1:
add_oper();
break;
case 2:
remove_oper();
break;
case 3:
select_oper();
break;
case 4:
printf("Showing the ranklist hurts students' self-esteem. Don't do that.\n");
break;
case 5:
score_oper();
break;
case 0:
return;
}
show_cd(); // 尾递归可以保证,一旦出现该函数下的return,则会导致所有函数全部终止
}
int main()
{
show_cd();
}
我得做法不是非常模拟,因为我一开始担心TLE问题,用STL搞了一些映射关系,这当然可能出问题,但是我真的没发现。Udebug没问题,样例没问题,交上去是WA不是PE