归一化处理

先计算平均值和方差,再按标准差对每个数据做平移缩放。

OJ: shumeng

题目 ID: CSP202206A

难度:入门

标签:模拟数学浮点数

日期: 2026-07-31 16:21

形式化题目

给定 nn 个整数 a1,a2,,ana_1,a_2,\dots,a_n,先求平均值

aˉ=1ni=1nai\bar a=\frac{1}{n}\sum_{i=1}^{n}a_i

和方差

D(a)=1ni=1n(aiaˉ)2,D(a)=\frac{1}{n}\sum_{i=1}^{n}(a_i-\bar a)^2,

再对每个元素输出

f(ai)=aiaˉD(a),f(a_i)=\frac{a_i-\bar a}{\sqrt{D(a)}},

使得输出序列的平均值为 00、方差为 11。题目保证 D(a)1D(a)\ge 1

思路

归一化处理分成三步,全部按数学定义直接计算即可。

第一步:求平均值

读入数据时同时累加,最后除以 nn 得到平均值 aˉ\bar a

第二步:求方差和标准差

先按定义累加 (aiaˉ)2(a_i-\bar a)^2,再除以 nn 得到方差 D(a)D(a)。标准差就是方差的平方根 D(a)\sqrt{D(a)}

第三步:逐项归一化输出

每一项都执行平移(减均值)和缩放(除以标准差),输出的就是均值为 00、方差为 11 的标准化序列。

注意浮点数使用 double 存储,输出保留足够的有效数字位数。

代码

cpp
/**
 * Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
 * rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
 * rainboy的学习导航网站: https://idx.roj.ac.cn
 * create_at: 2026-07-31 16:21
 * update_at: 2026-08-17 22:40
 */
#include <bits/stdc++.h>
using namespace std;

const int MAXN = 1005;

int n;
double a[MAXN];   // 原始整数数据
double average;   // 平均值
double variance;  // 方差

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

    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> a[i];
        average += a[i];
    }
    average /= n;

    // 按定义累加平方偏差,得到方差 D(a)
    for (int i = 0; i < n; i++) {
        variance += (a[i] - average) * (a[i] - average);
    }
    variance /= n;

    // 归一化公式:f(a[i]) = (a[i]-均值) / 标准差
    double deviation = sqrt(variance);
    cout << setprecision(17);
    for (int i = 0; i < n; i++) {
        cout << (a[i] - average) / deviation << '\n';
    }

    return 0;
}

复杂度

只做两次线性扫描,时间复杂度为 O(n)O(n);只需存储原数据,空间复杂度为 O(n)O(n)

总结

归一化公式的分子负责消去均值,分母负责把方差缩放为 1。题目保证方差非零,因此无需处理除零的边界情况。