#HT1056. 标准差

标准差

UPDATE(2021.08.06 09:58): 由于评测机压力带来的评测波动已不可忽视,本题将时间限制由 500ms 调整到了 1000ms

题目背景

标准差是一组数值自平均值分散开来的程度的一种测量观念。一个较大的标准差,代表大部分的数值和其平均值之间差异较大;一个较小的标准差,代表这些数值较接近平均值。

题目描述

本题采用 NOI 系列赛事常见的“文件输入输出”模式评测

输入文件名:sigma.in,输出文件名:sigma.out

输入 nn 个数,第 ii 个数为 aia_i,输出这 nn 个数的标准差(保留两位小数)。

标准差为方差的算数平方根,方差为每个数与平均数的差的平方之和除以数的个数。

比如五个数 3,2,7,6,83, 2, 7, 6, 8 时:

平均数μ=3+2+7+6+85=5.2\text{平均数}\mu=\frac{3+2+7+6+8}{5}=5.2

方差σ2=(35.2)2+(25.2)2+(75.2)2+(65.2)2+(85.2)25=5.36\text{方差} \sigma^2 = \frac{(3-5.2)^2+(2-5.2)^2+(7-5.2)^2+(6-5.2)^2+(8-5.2)^2}{5}=5.36

标准差σ=5.362.3151673805580\text{标准差}\sigma = \sqrt{5.36} \approx 2.3151673805580

用数学符号表示的话,可以表示为:

平均数μ=Σi=1nain\text{平均数} \mu =\frac{\Sigma_{i=1}^{n}{a_i}}{n}

方差σ2=Σi=1n(aiμ)n\text{方差} \sigma^2 =\frac{\Sigma_{i=1}^{n}{(a_i-\mu)}}{n}

标准差σ=σ2\text{标准差} \sigma =\sqrt{\sigma^2}

输入格式

输入第一行为一个整数 nn,表示有 nn 个数。

输入第二行为空格隔开的 nn 个整数,第 ii 个整数为 aia_i

输出格式

输出一行,为保留了两位小数的标准差。

样例

5
3 2 7 6 8
2.32
5
2 2 2 2 2 
0.00

数据范围

对于 60%60\% 的数据:1n10001\le n \le 1000

对于 100%100\% 的数据:1n5×1061\le n \le 5\times 10^61ai1041\le a_i\le 10^4

提示

文件输入输出

文件输入输出是 NOI 系列赛事常见的一种输入输出模式,题目中会写明输入及输出的文件名。写代码时只需要正常完成后,在 main() 函数的开始加入两行语句即可。

#include <cstdio>
...
int main(){
    freopen("输入文件名", "r", stdin);
    freopen("输出文件名", "w", stdout);
    ...
}

调试时可以先把这两行注释掉,调试成功后提交前取消注释即可。

如果使用 dev-cpp 等 IDE 编写代码,也可以在源代码文件相同的目录下,创建一个输入文件名的同名文件,用记事本打开后,写上样例输入,这样编译运行程序后,会自动创建一个输出文件名的文件,用记事本打开后就是你的程序的输出。

输入输出加速

本题输入输出量非常大,可以按照下列方式加速输入输出。

方案1

头文件加入 #include <cstdio>,然后仅使用 scanfprintf 进行输入输出。

方案2

main() 函数的开始加入两行代码。这两行代码可以关闭输入输出流同步,解除 cincout 绑定。

...
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    ...
}

然后仅使用cincout进行输入输出,且所有换行使用 '\n' ,不使用 endl 即可。

如果再搭配上文件输入输出,则 main() 函数的开始可以这样写:

...
int main(){
    freopen("输入文件名", "r", stdin);
    freopen("输出文件名", "w", stdout);
    ios::sync_with_stdio(false);
    cin.tie(0);
    ...
}

保留 xx 位小数的方法

方案 1

  • 头文件:#include <cstdio>
  • 语句: printf("%.xf", a);

方案 2

  • 头文件:#include<iostream>#include<iomanip>
  • 语句:cout << fixed << setprecision(x) << a;

注意

如果题目说保留 xx 位小数,那么就按照这种方式输出就可以了。

但是需要注意的是,这种方式并不是我们直观中的四舍五入。

对于 44 舍和 66 入的部分是没有问题的,对于舍入位是 55,且后面还有大于 00 的数位时也是没有问题的。但如果舍入位是 55 且后没有其他数了,那么有可能会有两个小问题。

首先这种情况下,如果是 double 类型可以精确储存的数,那么会舍入到最接近的偶数数位,比如在保留 00 位小数的情况下:

  • 0.50.5 -> 00
  • 1.51.5 -> 22
  • 2.52.5 -> 22
  • 3.53.5 -> 44

保留 22 位小数的情况下:

  • 1.1251.125 -> 1.121.12
  • 1.3751.375 -> 1.381.38

如果是 double 类型无法无法精确储存的数,实际上储存的数可能会有一点点偏差,也会造成和我们所想不同。
比如如果输入 1.1151.115,那么保留 22 位小数输出的会是 1.111.11,因为保留 2020 位小数输出后,我们会发现实际储存的数大概是 1.114999999999999991121.11499999999999999112,执行的自然是 44 舍操作。