K-variance#11317

K-variance (Editorial)

Let’s consider the sum:

\sum_{i=1}^n (a_i - \bar{a})^2 = \sum_{i=1}^n \left(a_i - \frac{\sum_{i=1}^n a_i}{n} \right)^2 = \sum_{i=1}^n \left(a^2_i - \frac{2}{n} a_i \sum_{i=1}^n a_i + \frac{\left(\sum_{i=1}^n a_i \right)^2}{n^2} \right) = \\ \sum_{i=1}^n a^2_i - \frac{2}{n} \sum_{i=1}^n a_i \sum_{i=1}^n a_i + \frac{\left(\sum_{i=1}^n a_i \right)^2}{n} = \\ \sum_{i=1}^n a^2_i - \frac{2}{n} \left(\sum_{i=1}^n a_i \right)^2 + \frac{1}{n} \left(\sum_{i=1}^n a_i \right)^2 = \sum_{i=1}^n a^2_i - \frac{1}{n} \left(\sum_{i=1}^n a_i \right)^2

Now, the formula for variance can be rewritten as:

\sqrt{\sum_{i=1}^n (a_i - \bar{a})^2 \over n - 1} = \sqrt{\frac{\sum_{i=1}^n a^2_i - \frac{1}{n} \left(\sum_{i=1}^n a_i \right)^2}{n - 1}}

If we maintain the sum of the elements of the sequence \{a_i, a_{i+1}, ..., a_{i+k-1}\} (i.e. (a_i + a_{i+1} + ... + a_{i+k-1})) and the sum of their squares (a^2_i + a^2_{i+1} + ... + a^2_{i+k-1}), then it is possible to calculate the desired variance for the segment in constant time.

Example

Let's expand the numerator of the fraction in the variance n = 3:

\left(a_1 - \frac{a_1 + a_2 + a_3}{3}\right)^2 + \left(a_2 - \frac{a_1 + a_2 + a_3}{3}\right)^2 + \left(a_3 - \frac{a_1 + a_2 + a_3}{3}\right)^2 = \\ a_1^2 + a_2^2 + a_3^2 - 2a_1 \cdot \frac{a_1 + a_2 + a_3}{3} - 2a_2 \cdot \frac{a_1 + a_2 + a_3}{3} - 2a_3 \cdot \frac{a_1 + a_2 + a_3}{3} + \\ \left(\frac{a_1 + a_2 + a_3}{3}\right)^2 + \left(\frac{a_1 + a_2 + a_3}{3}\right)^2 + \left(\frac{a_1 + a_2 + a_3}{3}\right)^2 = \\ a_1^2 + a_2^2 + a_3^2 - \frac{2}{3}(a_1 + a_2 + a_3)(a_1 + a_2 + a_3) + 3 \cdot \left(\frac{a_1 + a_2 + a_3}{3}\right)^2 = \\ a_1^2 + a_2^2 + a_3^2 - \frac{2}{3}(a_1 + a_2 + a_3)^2 + \frac{1}{3}(a_1 + a_2 + a_3)^2 = \\ a_1^2 + a_2^2 + a_3^2 - \frac{1}{3}(a_1 + a_2 + a_3)^2

Algorithm implementation

Read the input data.

scanf("%d %d", &n, &k);
a.resize(n);
for (i = 0; i < n; i++)
  scanf("%d", &a[i]);

On the segment [i - k + 1; i] let's maintain two variables:

sum = sum2 = 0;

Iterate through the elements of the sequence.

for (i = 0; i < n; i++)
{

Update the values of and .

  sum += a[i];
  sum2 += a[i] * a[i];

If there is a window [i - k + 1; i] of length , print the result for it.

  if (i >= k - 1)
  {
    printf("%lf\n", sqrt((sum2 - (sum * sum) / k) / (k - 1)));

Remove the element with index i - k + 1 from the considered sequence.

    sum -= a[i - k + 1];
    sum2 -= a[i - k + 1] * a[i - k + 1];
  }
}