P8113 [Cnoi2021] 自我主义的平衡者 题解
又是一道 (๑•ᴗ•๑) 的贪心题。题解区的好多题解写的都不详细,在这里严谨证明一下。
首先通过分析样例或者猜测,是很容易得到结论的:若要取最大值,则将序列从小到大排序;否则从大到小排序。
证明:
首先证明取最大平均值时的正确性。我们使用邻项交换法。
假设现在在序列中存在
首先考虑不交换时的贡献。当枚举到
其次考虑交换
那不增加时呢?有同学可能会说,由于不交换时答案变大了,平均值也会变大,那么后面就相比交换时取值的概率减小了。事实上,如果存在这样一种情况,即假若交换时,在后面某位置
综上,此条件下,不交换不会劣化答案。
-
a_i \leq s \leq a_{i+1}
不交换时,在第
交换时,在第
综上,此情况下,不交换和交换答案贡献相同。
-
a_i \leq a_{i+1} \leq s
不交换时,
交换时,
综上,不交换不会劣化答案。
可以用数学归纳法推到到整个序列。
对于求最小值时,也可以类比上面的证明方法,这里就省略了。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
#define int long long
const int N = 100005;
const double eps = 1e-14;
int n, m, sum = 0, a[N];
double avr = 0.0;
signed main(){
scanf("%lld %lld", &n, &m);
for(int i = 1; i <= n; i ++) scanf("%lld", &a[i]);
sort(a + 1, a + n + 1);
for(int i = 1; i <= n; i ++){
if(a[i] * 1.0 - avr > eps || fabs(a[i] * 1.0 - avr) < eps) sum += m;
avr = 1.0 * sum / (1.0 * i);
}
printf("%.2lf ", avr); sum = 0;
for(int i = n; i >= 1; i --){
if(a[i] * 1.0 - avr > eps || fabs(a[i] * 1.0 - avr) < eps) sum += m;
avr = 1.0 * sum / (1.0 * (n - i + 1));
}
printf("%.2lf\n", avr);
return 0;
}