(Updated space 2020.11.26) 修改了代码中的一些错误
解题思路
这道题是华一高2020级信息学竞赛班在八月份一次考试中的T3。
作为一名新初一学生,在题目里看到这么复杂的数学公式时我的心情是崩溃的。
读题完全在读是天书
但其实这题也没有那么难,裸的模拟。
首先,解释一下我定义的变量。
struct stures{ // 存储每个选手的数据
int id; // 选手编号
double yv; // 总位置分
double sumv; // 总分
}res[1005];
int n; // 题目中N
int x[1005][10] = {}; // 题目中x
double y[1005][10] = {}; // 题目中y
double avg[10] = {}; // 题目中avg
接下来我们用文字语言来解释一下那些求和公式。
-
第 (j) 项竞赛的平均分 $ avg_j = frac{1}{N} sum_{i=1}^N x_{ij} $
求平均分应该没有不会的吧。将每位选手第(j)项竞赛的分数加起来,除以选手个数就是第(j)项竞赛的平均分了。
代码实现:
for(int i = 0; i < 8; i++){ // 算均分 for(int j = 0; j < n; j++) avg[i] += x[j][i]; avg[i] /= n; }
-
选手 (i) 的总分 (sumx_i = sum_{j=1}^8 x_{ij})
这也不难理解,将选手每项竞赛的分数加起来就是了。
代码实现:
for(int i = 0; i < n; i++) for(int j = 0; j < 8; j++) // 算总分 res[i].sumv += x[i][j];
-
选手 (i) 第 (j) 项竞赛的位置分
[y_{ij}=left{egin{array}{l}{0,left(sum_{j=1}^{N}left|x_{ij}-a v g_{j} ight|=0 ight)} \ {frac{x_{ij}-a v g_{j}}{left(frac{1}{N} sum_{i=1}^{N}left|x_{ij}-a v g_{j} ight| ight.},left(sum_{i=1}^{N}left|x_{ij}-a v g_{j} ight| eq 0 ight)}end{array} ight. ]这个有点复杂,首先来弄懂后面括号的内容。
首先,
#define
分差 竞赛得分与均
分的差
$sum_{j=1}^{N}left|x_{ij}-a v g_{j}
ight|$这个式子就是选手$j$的分差之和。
若分差之和为$0$,则选手$i$竞赛$j$位置值为$0$。
若分差之和不为$0$,则位置值取选手$i$竞赛$j$的分差除以选手$i$所有竞赛分差的平均值。
读不懂就仔细多读几遍吧,我写的不好。
代码实现:
```cpp
for(int i = 0; i < 8; i++) for(int j = 0; j < n; j++){ // 算位置分
for(int k = 0; k < n; k++) y[j][i] += abs(x[k][i] - avg[i]);
if(y[j][i] != 0) y[j][i] = (x[j][i] - avg[i]) / (y[j][i] / n);
}
```
-
选手 (i) 的总位置分 (sumy_i = sum_{k=1}^3 y_{jk} + 0.8 sum_{k=4}^8 y_{jk})
也就是说,在总位置分中,前三项竞赛的位置分权值为1,后五项的权值为0.8,求和即可。
代码实现:
for(int i = 0; i < n; i++){ // 算总位置分 res[i].id = i; res[i].sumv = 0; for(int j = 0; j < 3; j++) res[i].yv += y[i][j]; for(int j = 3; j < 8; j++) res[i].yv += 0.8 * y[i][j]; }
在这里顺便为res数组作初始化
以上工作做完以后,我们再根据排名规则写一个cmp
函数:
bool cmp(stures r1, stures r2){
if(r1.yv != r2.yv) return r1.yv > r2.yv;
else if(r1.sumv != r2.sumv) return r1.sumv > r2.sumv;
else return r1.id < r2.id;
}
就是这样,(THE space END)
(AC space CODE)
#include<bits/stdc++.h>
using namespace std;
struct stures{
int id;
double yv, sumv;
}res[1005];
bool cmp(stures r1, stures r2){
if(r1.yv != r2.yv) return r1.yv > r2.yv;
else if(r1.sumv != r2.sumv) return r1.sumv > r2.sumv;
else return r1.id < r2.id;
}
int main(){
// freopen("ranking.in", "r", stdin);
// freopen("ranking.out", "w", stdout);
int n, x[1005][10] = {};
double y[1005][10] = {}, avg[10] = {};
cin >> n;
for(int i = 0; i < n; i++) for(int j = 0; j < 8; j++) cin >> x[i][j]; // 输入
for(int i = 0; i < 8; i++){ // 算均分
for(int j = 0; j < n; j++) avg[i] += x[j][i];
avg[i] /= n;
}
for(int i = 0; i < 8; i++) for(int j = 0; j < n; j++){ // 算位置分
for(int k = 0; k < n; k++) y[j][i] += abs(x[k][i] - avg[i]);
if(y[j][i] != 0) y[j][i] = (x[j][i] - avg[i]) / (y[j][i] / n);
}
for(int i = 0; i < n; i++){ // 算总位置分
res[i].id = i;
res[i].sumv = 0;
for(int j = 0; j < 3; j++) res[i].yv += y[i][j];
for(int j = 3; j < 8; j++) res[i].yv += 0.8 * y[i][j];
}
for(int i = 0; i < n; i++) for(int j = 0; j < 8; j++) // 算总分
res[i].sumv += x[i][j];
sort(res, res+n, cmp); // 快排
for(int i = 0; i < n; i++) cout << res[i].id+1 << endl; // 输出
return 0;
}
- 用时 89ms
- 内存 832.00KB
我这代码效率真的低