当前位置: 首页 > news >正文

《P1471 方差》

题目背景

滚粗了的 HansBug 在收拾旧数学书,然而他发现了什么奇妙的东西。

题目描述

蒟蒻 HansBug 在一本数学书里面发现了一个神奇的数列,包含 N 个实数。他想算算这个数列的平均数和方差。

输入格式

第一行包含两个正整数 N,M,分别表示数列中实数的个数和操作的个数。

第二行包含 N 个实数,其中第 i 个实数表示数列的第 i 项。

接下来 M 行,每行为一条操作,格式为以下三种之一:

操作 1:1 x y k ,表示将第 x 到第 y 项每项加上 k,k 为一实数。
操作 2:2 x y ,表示求出第 x 到第 y 项这一子数列的平均数。
操作 3:3 x y ,表示求出第 x 到第 y 项这一子数列的方差。

输出格式

输出包含若干行,每行为一个实数,即依次为每一次操作 2 或操作 3 所得的结果(所有结果四舍五入保留 4 位小数)。

输入输出样例

输入 #1复制

5 5
1 5 4 2 3
2 1 4
3 1 5
1 1 1 1
1 2 2 -1
3 1 5

输出 #1复制

3.0000
2.0000
0.8000

说明/提示

关于方差:对于一个有 n 项的数列 A,其方差 s2 定义如下:

s2=n1​i=1∑n​(Ai​−A)2

其中 A 表示数列 A 的平均数,Ai​ 表示数列 A 的第 i 项。

样例说明:

操作步骤输入内容操作要求数列输出结果说明
0--1 5 4 2 3--
12 1 4求 [1,4] 内所有数字的平均数1 5 4 2 33.0000平均数 =(1+5+4+2)÷4=3.0000
23 1 5求 [1,5] 内所有数字的方差1 5 4 2 32.0000平均数 =(1+5+4+2+3)÷5=3,方差 =((1−3)2+(5−3)2+(4−3)2+(2−3)2+(3−3)2)÷5=2.0000
31 1 1 1将 [1,1] 内所有数字加 12 5 4 2 3--
41 2 2 -1将 [2,2] 内所有数字加 −12 4 4 2 3--
53 1 5求 [1,5] 内所有数字的方差2 4 4 2 30.8000平均数 =(2+4+4+2+3)÷5=3,方差 =((2−3)2+(4−3)2+(4−3)2+(2−3)2+(3−3)2)÷5=0.8000

数据规模:

数据点NM备注
1∼3N≤8M≤15-
4∼7N≤105M≤105不包含操作 3
8∼10N≤105M≤105

-

代码实现;

#include <iostream>
#include <iomanip>
#include <vector>
using namespace std;

struct SegmentTreeNode {
    int left, right;         // 区间左右端点
    double sum;              // 区间和
    double squareSum;       // 区间平方和
    SegmentTreeNode *leftChild, *rightChild;
    
    SegmentTreeNode(int l, int r) : left(l), right(r), sum(0), squareSum(0) {
        leftChild = NULL;    // 使用NULL替代nullptr
        rightChild = NULL;   // 使用NULL替代nullptr
    }
};

// 构建线段树
void build(SegmentTreeNode* node, const vector<double>& arr) {
    if (node->left == node->right) {
        node->sum = arr[node->left - 1];
        node->squareSum = arr[node->left - 1] * arr[node->left - 1];
        return;
    }
    
    int mid = (node->left + node->right) / 2;
    node->leftChild = new SegmentTreeNode(node->left, mid);
    node->rightChild = new SegmentTreeNode(mid + 1, node->right);
    
    build(node->leftChild, arr);
    build(node->rightChild, arr);
    
    node->sum = node->leftChild->sum + node->rightChild->sum;
    node->squareSum = node->leftChild->squareSum + node->rightChild->squareSum;
}

// 区间更新:将[L, R]区间内的每个数加k
void update(SegmentTreeNode* node, int L, int R, double k) {
    if (node->right < L || node->left > R) return;
    if (L <= node->left && node->right <= R) {
        // 区间完全包含,更新和与平方和
        node->sum += k * (node->right - node->left + 1);
        node->squareSum += 2 * k * node->sum - k * k * (node->right - node->left + 1);
        return;
    }
    
    update(node->leftChild, L, R, k);
    update(node->rightChild, L, R, k);
    
    node->sum = node->leftChild->sum + node->rightChild->sum;
    node->squareSum = node->leftChild->squareSum + node->rightChild->squareSum;
}

// 区间查询:查询[L, R]的和与平方和
void query(SegmentTreeNode* node, int L, int R, double& sum, double& squareSum) {
    if (node->right < L || node->left > R) return;
    if (L <= node->left && node->right <= R) {
        sum += node->sum;
        squareSum += node->squareSum;
        return;
    }
    
    query(node->leftChild, L, R, sum, squareSum);
    query(node->rightChild, L, R, sum, squareSum);
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);              // 用0替代nullptr
    cout << fixed << setprecision(4);
    
    int n, m;
    cin >> n >> m;
    
    vector<double> arr(n);
    for (int i = 0; i < n; i++) {
        cin >> arr[i];
    }
    
    // 构建线段树
    SegmentTreeNode* root = new SegmentTreeNode(1, n);
    build(root, arr);
    
    // 处理操作
    for (int i = 0; i < m; i++) {
        int op;
        cin >> op;
        
        if (op == 1) {
            int x, y;
            double k;
            cin >> x >> y >> k;
            update(root, x, y, k);
        } else if (op == 2) {
            int x, y;
            cin >> x >> y;
            double sum = 0, squareSum = 0;
            query(root, x, y, sum, squareSum);
            double average = sum / (y - x + 1);
            cout << average << endl;
        } else if (op == 3) {
            int x, y;
            cin >> x >> y;
            double sum = 0, squareSum = 0;
            query(root, x, y, sum, squareSum);
            int count = y - x + 1;
            double average = sum / count;
            double variance = (squareSum - count * average * average) / count;
            cout << variance << endl;
        }
    }
    
    return 0;
}

相关文章:

  • C++11 <chrono> 库特性:从入门到精通
  • 深入解析RNN模型:应用、结构与构建实战
  • swift 对象转Json
  • ArcGIS Pro利用擦除工具,矢量要素消除另一矢量部分区域
  • QT 国际化 翻译 总结
  • Buildroot 2025.05 中文手册【AI高质量翻译】
  • 哪家香港站群服务器比较好用?
  • 生成树基础实验
  • 机器学习4——参数估计之贝叶斯估计
  • 工作台-02.代码开发
  • 学习日记-day38-spring-6.27
  • Veo 3 视频生成大模型完整操作教程(2025)
  • 元宇宙与人工智能的融合:从虚拟世界到智能生态的IT新革命
  • 社会工程--如何使用对方的语言
  • 汇编8086:解决创建、写入文档在临时文档的问题 | 汇编实现创建文件永久保存
  • 【innovus基础】- 最基本的timing工具自动修复方法
  • Unity性能优化-渲染模块(1)-CPU侧(1)-优化方向
  • 每日八股文6.28
  • [Python]-基础篇1- 从零开始的Python入门指南
  • 【编译原理】第一章 习题