洛谷P1471 方差

题目概括

题目描述

蒟蒻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

解题报告

题意理解

  1. 区间加一个实数
  2. 区间求平均数
  3. 区间求方差

算法解析

首先我们来推倒公式。

先拿出方差公式

\[S^2 = \frac{1}{n} * [(x_1 - \overline{x})^2 + (x_2 - \overline{x})^2 + ...+(x_n - \overline{x})^2 ] \]

根据完全平方公式:

\[(a + b)^2 = a^2 + 2ab + b^2 \]

因此带入参数进去

\[(x_1-\overline{x})^2=x_1^2+2x\overline{x}+\overline{x}^2 \]

接着处理公式

\[S^2 = \frac{1}{n} * ({x_1}^2 - 2{x_1}\overline{x} + {\overline{x}^2} + {x_2}^2 - 2{x_2}\overline{x} + {\overline{x}^2} + ... + {x_n}^2 - 2{x_n}\overline{x} + {\overline{x}^2}) \]

然后稍微整理一下

\[S^2 = \frac{1}{n} * [({x_1}^2 + {x_2}^2 + ... + {x_n}^2)-2\overline{x}(x_1 + x_2 + ...+x_n) + n\overline{x}^2] \]

然后我们通过平均数公式可得

\[n\overline{x} = x_1 + x_2 + ... + x_n \]

将上面公式,导入方差公式

\[S^2 = \frac{1}{n} * [({x_1}^2 + {x_2}^2 + ... + {x_n}^2)-2n\overline{x}^2 + n\overline{x}^2] \]

代入后

\[S^2 = \frac{1}{n} * [({x_1}^2 + {x_2}^2 + ... + {x_n}^2)-n\overline{x}^2] \]

因此我们得出了最后的公式

\[S^2 = \frac{({x_1}^2 + {x_2}^2 + ... + {x_n}^2)}{n} - \overline{x}^2 \]

接着我们着重分析分子部分。

\[x_1^2+x_2^2+\dots+x_k^2 \\\\ \]

现在所有数增加\(b\),则

\[(x_1+b)^2+(x_2+b)^2+\dots +(x_k+b)^2 \\\\ \]

然后定义一下

\[令sum1=x_1+x_2+\dots+x_k \\\\ 令sum2=x_1^2+x_2^2+\dots+x_k^2 \\\\ \]

由之前的完全平方公式可得:

\[(x_i+b)^2=x_i^2+2 \times x_i \times b+b^2\\\\ \]

然后带入之前的部分

\[(x_1^2+x_2^2+\dots+x_k^2)+2b \times (x_1+x_2+\dots+x_k)+(b^2 \times k) \\\\ \]

最后载入定义

\[sum2+2b \times sum1+b^2 \times k \\\\ \]

我们终于终于终于将公式打完了。。。。。。

现在我们就可以通过,线段树来维护本题目了。

  1. 维护平方和
  2. 维护区间和

请注意,在这里,我们肯定是要开两个\(Lazy\)标记的;。

但是要记住平方和的懒惰标记,是绝对高于区间和的懒惰标记。

因为,通过公式可得,平方和的修改,是要先使用区间和的。

如果说先修改区间和,那么平方和的修改必然出现问题。


代码解释

#include <bits/stdc++.h>
using namespace std;
#define Lson rt<<1,l,mid
#define Rson rt<<1 | 1,mid+1,r
#define mid  (l+r>>1)
#define len  (r-l+1)
const int N=1e5+20;
int n,m;
struct node
{
	double lazy,sum;
} t1[N<<2],t2[N<<2];
double a[N];
inline void Push_up(int rt)
{
	t1[rt].sum=t1[rt<<1].sum+t1[rt<<1 | 1].sum;
	t2[rt].sum=t2[rt<<1].sum+t2[rt<<1 | 1].sum;
}
void build(int rt,int l,int r)
{
	if (l==r)
	{
		t1[rt].sum=a[l];
		t2[rt].sum=a[l]*a[l];
		return;
	}
	build(Lson);
	build(Rson);
	Push_up(rt);
}
inline void Push_down(int rt,int l,int r)
{
	if (!(t1[rt].lazy || t2[rt].lazy))
		return ;
	t2[rt<<1].lazy+=t2[rt].lazy;
	t2[rt<<1].sum+=t1[rt<<1].sum*(t2[rt].lazy*2)+(mid-l+1)*(t2[rt].lazy*t2[rt].lazy);
	t2[rt<<1 | 1].lazy+=t2[rt].lazy;
	t2[rt<<1 | 1].sum+=t1[rt<<1 | 1].sum*(t2[rt].lazy*2)+(r-mid)*(t2[rt].lazy*t2[rt].lazy);
	t2[rt].lazy=0;
	t1[rt<<1].lazy+=t1[rt].lazy;
	t1[rt<<1].sum+=(mid-l+1)*t1[rt].lazy;
	t1[rt<<1 | 1].lazy+=t1[rt].lazy;
	t1[rt<<1 | 1].sum+=(r-mid)*t1[rt].lazy;
	t1[rt].lazy=0;
}
double Query(int rt,int l,int r,int L,int R,int x)
{
	if (L<=l && r<=R)
		return x==1 ? t1[rt].sum:t2[rt].sum;
	double ans=0;
	Push_down(rt,l,r);
	if (L<=mid)
		ans+=Query(Lson,L,R,x);
	if (R>mid)
		ans+=Query(Rson,L,R,x);
	return ans;
}
void Update(int rt,int l,int r,int L,int R,double v)
{
	if (L<=l && r<=R)
	{
		t2[rt].lazy+=v;
		t2[rt].sum+=t1[rt].sum*(v*2)+len*(v*v);
		t1[rt].lazy+=v;
		t1[rt].sum+=len*v;
		return ;
	}
	Push_down(rt,l,r);
	if (L<=mid)
		Update(Lson,L,R,v);
	if (R>mid)
		Update(Rson,L,R,v);
	Push_up(rt);
}
inline void init()
{
//	freopen("data.in","r",stdin);
//	freopen("a.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1; i<=n; i++)
		scanf("%lf",&a[i]);
	build(1,1,n);
	while(m--)
	{
		int x,a,b;
		scanf("%d%d%d",&x,&a,&b);
		if (x==1)
		{
			double c;
			scanf("%lf",&c);
			Update(1,1,n,a,b,c);
		}
		if (x==2)
			printf("%.4lf\n",Query(1,1,n,a,b,1)/((b-a+1)*1.0));
		if (x==3)
		{
			double cnt=(b-a+1)*1.0;
			double ans=Query(1,1,n,a,b,2)/cnt,x_ba=Query(1,1,n,a,b,1)/cnt;
			double ans2=x_ba*x_ba;
			ans-=ans2;
			printf("%.4lf\n",ans);
		}
	}
}
signed main()
{
	init();
	return 0;
}
posted @ 2019-11-12 21:28  秦淮岸灯火阑珊  阅读(362)  评论(0编辑  收藏  举报