题解:B3968 [GESP202403 五级] 成绩排序
首先看到这道题,知道这是一个排序夹杂了结构体的题。
然而看到排序规则时彻底懵了:
- 比较总分,高者靠前;
- 如果总分相同,则比较语文和数学两科的总分,高者靠前;
- 如果仍相同,则比较语文和数学两科的最高分,高者靠前;
- 如果仍相同,则二人并列。
于是在经过了 114514 次思考后,有了下面的代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
struct student
{
int chn=0;//语文
int mah=0;//数学
int eng=0;//英语
int sum=0;//总分
int num=0;//序号
int pm=0;//排名
};
bool cmp1(student a,student b)
{
if(a.sum!=b.sum)//对应规则 1
return a.sum>b.sum;
else if((a.mah+a.chn)!=(b.mah+b.chn))//对应规则 2
return (a.mah+a.chn)>(b.mah+b.chn);
else if(max(a.mah,a.chn)!=max(b.mah,b.chn))//对应规则 3
return max(a.mah,a.chn)>max(b.mah,b.chn);
else//对应……?(挖个坑,后文再填)
return a.num<b.num;
}
main()
{
student stu[200005];
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>stu[i].chn>>stu[i].mah>>stu[i].eng;
stu[i].sum=stu[i].chn+stu[i].mah+stu[i].eng;
stu[i].num=i;
}
sort(stu+1,stu+1+n,cmp1);
for(int i=1;i<=n;i++)
stu[i].pm=i;
for(int i=1;i<=n;i++)
cout<<stu[i].pm<<"\n";
return 0;
}
然而结局嘛……
不用说的,全 WA 了。
为何?
看了一下输出格式:
注意:请不要按排名输出同学的序号,而是按同学的顺序输出他们各自的排名。
原来如此。
又想了 1919810 次后,就有了下面的代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
struct student
{
int chn=0,mah=0,eng=0,sum=0,num=0;
int pm=0;
};
bool cmp1(student a,student b)
{
if(a.sum!=b.sum)
return a.sum>b.sum;
else if((a.mah+a.chn)!=(b.mah+b.chn))
return (a.mah+a.chn)>(b.mah+b.chn);
else if(max(a.mah,a.chn)!=max(b.mah,b.chn))
return max(a.mah,a.chn)>max(b.mah,b.chn);
else
return a.num<b.num;
}
bool cmp2(student a,student b)
{
return a.num<b.num;
}
main()
{
student stu[200005];
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>stu[i].chn>>stu[i].mah>>stu[i].eng;
stu[i].sum=stu[i].chn+stu[i].mah+stu[i].eng;
stu[i].num=i;
}
sort(stu+1,stu+1+n,cmp1);
for(int i=1;i<=n;i++)
stu[i].pm=i;
sort(stu+1,stu+1+n,cmp2);
for(int i=1;i<=n;i++)
cout<<stu[i].pm<<"\n";
return 0;
}
这里多了的 bool cmp2(student a,student b) 和 sort(stu+1,stu+1+n,cmp2) 就是用来实现这一功能的。
然而……
还是全 WA 了。
又是为何?
仔细再读一遍题目:
你需要输出每位同学的排名,如遇
x 人并列,则他们排名相同,并留空后面的(x-1) 个名次。
那么,具体怎么实现?
这是我想了 956382 次后想出来的做法:
首先,在结构体里多定义一个 bool 型变量,并赋值为 false:
struct student
{
int chn=0,mah=0,eng=0,sum=0,num=0;
int pm=0;
bool iscp=0;
};
然后再把排序规则的最后一个 else 改一改:
else//填前面的坑,做标记,对应规则 4
{
if(a.num<b.num)
b.iscp=1;
else
a.iscp=1;
return a.num<b.num;
}
接着在两个 sort 语句间的 for 循环改一改:
for(int i=1;i<=n;i++)//查重
{
if(stu[i].pm) continue;//关键,做到留空名次
else
{
stu[i].pm=i;
int cur=1;
while(stu[i+cur].iscp)//关键,做到排名相同
{
stu[i+cur].pm=stu[i].pm;
cur++;
}
}
}
这样便大功告成了!
最后,把这些整合一下,AC 代码就有了!
代码如下:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
struct student
{
int chn=0,mah=0,eng=0,sum=0,num=0;
int pm=0;
bool iscp=0;
};
bool cmp1(student a,student b)
{
if(a.sum!=b.sum)
return a.sum>b.sum;
else if((a.mah+a.chn)!=(b.mah+b.chn))
return (a.mah+a.chn)>(b.mah+b.chn);
else if(max(a.mah,a.chn)!=max(b.mah,b.chn))
return max(a.mah,a.chn)>max(b.mah,b.chn);
else
{
if(a.num<b.num)
b.iscp=1;
else
a.iscp=1;
return a.num<b.num;
}
}
bool cmp2(student a,student b)
{
return a.num<b.num;
}
main()
{
student stu[200005];
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>stu[i].chn>>stu[i].mah>>stu[i].eng;
stu[i].sum=stu[i].chn+stu[i].mah+stu[i].eng;
stu[i].num=i;
}
sort(stu+1,stu+1+n,cmp1);
for(int i=1;i<=n;i++)
{
if(stu[i].pm) continue;
else
{
stu[i].pm=i;
int cur=1;
while(stu[i+cur].iscp)
{
stu[i+cur].pm=stu[i].pm;
cur++;
}
}
}
sort(stu+1,stu+1+n,cmp2);
for(int i=1;i<=n;i++)
cout<<stu[i].pm<<"\n";
return 0;
}
(题解仅供参考,如有谬误或纰漏欢迎 at 我并指正)