统计量列表

题意

给定一个整数序列 arr 和一组窗口大小 windows。对于每个位置,以公共右边界为基准,对每个窗口大小取右对齐的子数组,分别计算 5 个统计量(mean、std、min、max、slope),然后按窗口顺序拼接成一行输出。

具体规则:

  • 公共右边界 ,窗口
  • 总行数 ,若 输出 []
  • std:样本标准差(ddof=1),窗口为 1 时等于 0
  • slope:最小二乘法斜率,,窗口为 1 或分母为 0 时等于 0
  • 数值格式:整数不带小数点;非整数最多 3 位小数,四舍五入,去掉末尾无意义的零

思路

这题没有什么算法上的难度,就是一道模拟题,但细节不少。你可以问自己几个问题来理清思路:

1. 窗口怎么对齐?

题目说"右对齐"——所有窗口共享同一个右边界 。大窗口的左边界更靠左,小窗口更靠右。第 行的

拿样例 [2, 4, 6, 8, 10, 12], [2, 4] 来说,,第 0 行

  • :取 arr[2..3] = [6, 8]
  • :取 arr[0..3] = [2, 4, 6, 8]

2. slope 怎么算?

标准最小二乘线性回归斜率。横坐标固定为 ,纵坐标是子数组的元素。公式:

$$

其中

3. 数值格式怎么处理?

这是最容易出错的地方。规则是:

  • 如果结果恰好是整数(比如 7.0),输出 7
  • 否则保留最多 3 位小数,去掉末尾的零(1.1001.12.582 保持不变)

Python 里可以先用 f"{x:.3f}",然后 rstrip('0').rstrip('.'),再判断是否为整数做特殊处理。

4. 整体流程?

对每行输入:

  1. 解析 arrwindows
  2. 计算 max_w 和行数 n
  3. 对每一行,算出右边界 ,对每个窗口切片,算 5 个统计量,拼接输出

时间复杂度 ,其中 是窗口数量, 是窗口大小,完全没有性能压力。

代码

import sys
from math import sqrt

def format_num(x):
    if x == int(x):
        return str(int(x))
    s = f"{x:.3f}"
    s = s.rstrip('0').rstrip('.')
    return s

def compute_stats(sub):
    w = len(sub)
    mean = sum(sub) / w
    if w == 1:
        std = 0
    else:
        variance = sum((v - mean) ** 2 for v in sub) / (w - 1)
        std = sqrt(variance)
    mn = min(sub)
    mx = max(sub)
    if w == 1:
        slope = 0
    else:
        x_mean = (w - 1) / 2.0
        num = sum(i * sub[i] for i in range(w)) - w * x_mean * mean
        den = sum(i * i for i in range(w)) - w * x_mean * x_mean
        slope = num / den if abs(den) > 1e-12 else 0
    return [mean, std, mn, mx, slope]

for line in sys.stdin:
    line = line.strip()
    if not line:
        continue
    parts = line.split('],')
    arr = list(map(int, parts[0].strip().strip('[').split(',')))
    windows = list(map(int, parts[1].strip().strip('[] ').split(',')))
    max_w = max(windows)
    n = len(arr) - max_w + 1
    if n <= 0:
        print("[]")
        continue
    for i in range(n):
        R = i + max_w - 1
        row = []
        for w in windows:
            left = R - w + 1
            row.extend(compute_stats(arr[left:R+1]))
        print("[" + ", ".join(format_num(v) for v in row) + "]")
#include <bits/stdc++.h>
using namespace std;

string formatNum(double x) {
    if (abs(x - round(x)) < 1e-9) return to_string((long long)round(x));
    char buf[64];
    sprintf(buf, "%.3f", x);
    string s(buf);
    size_t dot = s.find('.');
    if (dot != string::npos) {
        size_t last = s.size() - 1;
        while (last > dot && s[last] == '0') last--;
        if (last == dot) last--;
        s = s.substr(0, last + 1);
    }
    return s;
}

struct Stats { double mean, std_, mn, mx, slope; };

Stats computeStats(vector<int>& arr, int left, int right) {
    int w = right - left + 1;
    double sum = 0;
    int mn = INT_MAX, mx = INT_MIN;
    for (int i = left; i <= right; i++) {
        sum += arr[i]; mn = min(mn, arr[i]); mx = max(mx, arr[i]);
    }
    double mean = sum / w;
    double std_val = 0;
    if (w > 1) {
        double var = 0;
        for (int i = left; i <= right; i++) { double d = arr[i] - mean; var += d * d; }
        std_val = sqrt(var / (w - 1));
    }
    double slope = 0;
    if (w > 1) {
        double x_mean = (w - 1) / 2.0;
        double num = 0, den = 0;
        for (int i = 0; i < w; i++) { num += (double)i * arr[left + i]; den += (double)i * i; }
        num -= w * x_mean * mean; den -= w * x_mean * x_mean;
        if (abs(den) > 1e-12) slope = num / den;
    }
    return {mean, std_val, (double)mn, (double)mx, slope};
}

int main() {
    string line;
    while (getline(cin, line)) {
        if (line.empty()) continue;
        size_t p1 = line.find('['), p2 = line.find(']', p1);
        size_t p3 = line.find('[', p2), p4 = line.find(']', p3);
        string arrStr = line.substr(p1 + 1, p2 - p1 - 1);
        string winStr = line.substr(p3 + 1, p4 - p3 - 1);
        vector<int> arr, windows;
        { stringstream ss(arrStr); string t; while (getline(ss, t, ',')) arr.push_back(stoi(t)); }
        { stringstream ss(winStr); string t; while (getline(ss, t, ',')) windows.push_back(stoi(t)); }
        int maxW = *max_element(windows.begin(), windows.end());
        int n = (int)arr.size() - maxW + 1;
        if (n <= 0) { cout << "[]" << endl; continue; }
        for (int i = 0; i < n; i++) {
            int R = i + maxW - 1;
            vector<string> row;
            for (int w : windows) {
                int left = R - w + 1;
                Stats s = computeStats(arr, left, R);
                row.push_back(formatNum(s.mean));
                row.push_back(formatNum(s.std_));
                row.push_back(formatNum(s.mn));
                row.push_back(formatNum(s.mx));
                row.push_back(formatNum(s.slope));
            }
            cout << "[";
            for (int j = 0; j < (int)row.size(); j++) { if (j) cout << ", "; cout << row[j]; }
            cout << "]" << endl;
        }
    }
}