LuoguP5759 [NOI1997]竞赛排名 题解

有一场比赛有 \(n\) 个人参加,一共要参加 \(8\) 场比赛。已知第 \(i\) 位选手的第 \(j\) 场比赛拿了 \(x_{i,j}\) 分。另外还有一些重要指标:

  • \(j\) 场比赛的平均分 \(avg_j=\dfrac{\sum\limits_{i=1}^nx_{i,j}}{n}\)
  • \(i\) 位选手的总分 \(sum_{x_i}=\sum\limits_{j=1}^8x_{i,j}\)
  • \(i\) 位选手在第 \(j\) 场比赛的位置分 \(y_{i,j}=\begin{cases}0&\sum\limits_{i=1}^n|x_{i,j}-avg_j|=0\\\dfrac{n\times (x_{i,j}-avg_j)}{\sum\limits_{i=1}^n|x_{i,j}-avg_j|}&\sum\limits_{i=1}^n|x_{i,j}-avg_j|\neq 0\end{cases}\)
  • \(i\) 位选手的总位置分 \(sum_{y_i}=\sum\limits_{j=1}^3y_{i,j}+0.8\sum\limits_{j=4}^8y_{i,j}\)

排名的规则如下:

  • 总位置分高的选手名次在前;
  • 若两个或两个以上的选手总位置分相同,则总分高的选手名次在前;
  • 若两个或两个以上的选手总位置分和总分均相同,则编号在前的选手名次在前。

请求出第 \(1\sim n\) 名的选手编号。

数据范围:\(n\) 未知,但亲测 \(10^5\) 能过,\(0\leqslant x_{i,j}\leqslant 100\)

Solution

除了式子有些复杂之外,这题就是一道纯粹的模拟。我们直接开个结构体来存储每个选手的指标以及每种竞赛的指标,然后直接按照上面的公式计算,最后利用结构体的 \(\texttt{operator}\) 来排序之后直接输出就好。

Code

int n, x[100007][17], s[17];
double ave[17];
struct node {
	int sum, id;
	double pl[17], plsum;
	bool operator < (const node& rhs) const {
		if(plsum != rhs.plsum) return plsum > rhs.plsum;
		if(sum != rhs.sum) return sum > rhs.sum;
		return id < rhs.id;
	}
}a[100007];

int main() {
	scanf("%d", &n);
	for(int i = 1; i <= n; ++i) {
		a[i].id = i;
		for(int j = 1; j <= 8; ++j) {
			scanf("%d", &x[i][j]);
			s[j] += x[i][j];
			a[i].sum += x[i][j];
		}
	}
	for(int j = 1; j <= 8; ++j)
		ave[j] = s[j] * 1.0 / n;
    double tmpsum[17] = {0};
	for(int j = 1; j <= 8; ++j)
		for(int i = 1; i <= n; ++i)
			tmpsum[j] += abs(x[i][j] - ave[j]);
	for(int i = 1; i <= n; ++i) {
		for(int j = 1; j <= 8; ++j) {
			if(tmpsum[j] == 0) a[i].pl[j] = 0;
			else a[i].pl[j] = (x[i][j] - ave[j]) * n * 1.0 / tmpsum[j];
		}
		for(int j = 1; j <= 3; ++j) a[i].plsum += a[i].pl[j];
		for(int j = 4; j <= 8; ++j) a[i].plsum += a[i].pl[j] * 0.8;
	}
	sort(a + 1, a + n + 1);
	for(int i = 1; i <= n; ++i) printf("%d\n", a[i].id);
}
posted @ 2021-12-16 15:02  Eason_AC  阅读(103)  评论(0)    收藏  举报