1012 The Best Rank (25分)
题意
现已知n个考生的3门课分数C、M、E,而平均分数A可以由这3个分数得到。现在分别按这4个分数对n个考生从高到低排序,这样对每个考生来说,就会有4个排名且每个分数都会有一个排名。接下来会有m个查询,每个查询输入一个考生的ID,输出该考生4个排名中最高的那个排名及对应是A、C、M、E中的哪一个。如果对不同课程有相同排名的情况,则按优先级A>C>M>E输出;如果查询的考生ID不存在,则输出N/A。
毒瘤题。。。之后找机会重写下吧。。。毕竟现在的码风惨不忍睹,而且\(\color{green}{AcWing}\)上只过了\(3\)个点=_=
注意分数相同的同学名次相同,并且小于当前分数的同学的名次依次向后递进。
例如:1、1、3、4、5,而不是1、1、2、3、4。
const int N=2010;
struct Stu {
int c_rank,m_rank,e_rank,avg_rank;
}a[N];
PII c[N],m[N],e[N];
unordered_map<string,int> mp;
PDI avg[N];
int n,q;
int main()
{
cin>>n>>q;
for(int i=0;i<n;i++)
{
string id;
cin>>id>>c[i].fi>>m[i].fi>>e[i].fi;
avg[i].fi=(c[i].fi+m[i].fi+e[i].fi)/3.0;
mp[id]=i;
c[i].se=m[i].se=e[i].se=avg[i].se=i;
}
sort(c,c+n,greater<PII>());
sort(m,m+n,greater<PII>());
sort(e,e+n,greater<PII>());
sort(avg,avg+n,greater<PDI>());
int tot=1;
for(int i=0;i<n;i++)
{
if(i && c[i].fi == c[i-1].fi)
a[c[i].se].c_rank=a[c[i-1].se].c_rank;
else
a[c[i].se].c_rank=tot;
tot++;
}
tot=1;
for(int i=0;i<n;i++)
{
if(i && m[i].fi == m[i-1].fi)
a[m[i].se].m_rank=a[m[i-1].se].m_rank;
else
a[m[i].se].m_rank=tot;
tot++;
}
tot=1;
for(int i=0;i<n;i++)
{
if(i && e[i].fi == e[i-1].fi)
a[e[i].se].e_rank=a[e[i-1].se].e_rank;
else
a[e[i].se].e_rank=tot;
tot++;
}
tot=1;
for(int i=0;i<n;i++)
{
if(i && avg[i].fi == avg[i-1].fi)
a[avg[i].se].avg_rank=a[avg[i-1].se].avg_rank;
else
a[avg[i].se].avg_rank=tot;
tot++;
}
while(q--)
{
string id;
cin>>id;
if(!mp.count(id))
{
puts("N/A");
continue;
}
int x=mp[id];
int rank=min(min(a[x].c_rank,a[x].m_rank),min(a[x].e_rank,a[x].avg_rank));
if(a[x].avg_rank == rank)
cout<<rank<<' '<<'A'<<endl;
else if(a[x].c_rank == rank)
cout<<rank<<' '<<'C'<<endl;
else if(a[x].m_rank == rank)
cout<<rank<<' '<<'M'<<endl;
else
cout<<rank<<' '<<'E'<<endl;
}
//system("pause");
return 0;
}
\(update on 2021.2.14\)
情人节快乐!
思路
- 考虑到优先级为A>C>M>E,不妨在设置数组时就按这个顺序分配序号为0 ~ 3的元素,即0对应A、1对应C、2对应M及3对应E。
- 按顺序枚举A、C、M、E,对每个分数,将所有考生排序,并在Rank数组中记录排名。
- 在查询时,对读入的查询ID,先看其是否存在。如果存在,选出Rank[pos][0] ~ Rank[pos][3]中数字最小(即排名最高)的那个即可。
由于排序会改变\(a\)数组,因此在读入时需要记录下标位置\(pos\),再存储至Rank数组中对应\(pos\)的位置。
注意点
- 要注意优先级顺序是A>C>M>E,所以为了方便枚举,在设置数组时尽量把A放在C、M、E前面。
- 排名时,相同分数算作排名相同,所以91、90、 88、 88、84的排名应该算作1、2、3、3、5。在具体实现时,切记不要算作1、2、3、3、4。
- 本题没有明示平均分是否需要取整以及取整方式,根据题目描述中的例子可以看出是四舍五入。但本题采用向下取整的方式也能通过,或者采用更简洁的方式——不取平均,直接存储三门课的总分。
struct Stu {
string id;
int grade[4];
int pos;
}a[N];
int Rank[N][4];
unordered_map<string,Stu> mp;
char course[]={'A','C','M','E'};
int n,m;
int idx;
bool cmp(Stu &a, Stu &b)
{
return a.grade[idx] > b.grade[idx];
}
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++)
{
cin>>a[i].id>>a[i].grade[1]>>a[i].grade[2]>>a[i].grade[3];
a[i].pos=i;
for(int j=1;j<4;j++) a[i].grade[0]+=a[i].grade[j];
mp[a[i].id]=a[i];
}
for(idx=0;idx<4;idx++)
{
sort(a,a+n,cmp);
for(int i=0;i<n;i++)
{
if(i && a[i].grade[idx] == a[i-1].grade[idx])
Rank[a[i].pos][idx]=Rank[a[i-1].pos][idx];
else
Rank[a[i].pos][idx]=i+1;
}
}
while(m--)
{
string id;
cin>>id;
if(!mp.count(id)) puts("N/A");
else
{
int pos=mp[id].pos;
int minidx=0;
for(int i=1;i<4;i++)
if(Rank[pos][i] < Rank[pos][minidx])
minidx=i;
cout<<Rank[pos][minidx]<<' '<<course[minidx]<<endl;
}
}
//system("pause");
return 0;
}
至于\(\color{green}{AcWing}\)上只能过\(3\)个点,\(\color{green}{AcWing}\)上平均成绩为三科成绩平均值四舍五入取整的结果,所以加上下面一行就可以了。
a[i].grade[0]=round(a[i].grade[0]/3.0);