洛谷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
解题报告
题意理解
- 区间加一个实数
- 区间求平均数
- 区间求方差
算法解析
首先我们来推倒公式。
先拿出方差公式
\[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 \\\\
\]
我们终于终于终于将公式打完了。。。。。。
现在我们就可以通过,线段树来维护本题目了。
- 维护平方和
- 维护区间和
请注意,在这里,我们肯定是要开两个\(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;
}