「Solution」P5759 [NOI1997]竞赛排名

\(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\{\begin{array}{l}{0,\left(\sum_{j=1}^{N}\left|x_{ij}-a v g_{j}\right|=0\right)} \\ {\frac{x_{ij}-a v g_{j}}{\left(\frac{1}{N} \sum_{i=1}^{N}\left|x_{ij}-a v g_{j}\right|\right.},\left(\sum_{i=1}^{N}\left|x_{ij}-a v g_{j}\right| \neq 0\right)}\end{array}\right. \]

    这个有点复杂,首先来弄懂后面括号的内容。

    首先,#define 分差 竞赛得分与均

分的差

$\sum_{j=1}^{N}\left|x_{ij}-a v g_{j}\right|$这个式子就是选手$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

我这代码效率真的低

本蒟蒻第一篇题解,管理大大求通过

posted @ 2020-10-03 17:09  Liuxizai  阅读(135)  评论(0编辑  收藏  举报