好题集 (3) - LG P2122 还教室
题意:给定一数列,要求支持区间加法、区间方差、区间平均数。
首先做查询。平均数好做,考虑方差怎么搞。大力推柿子:
\[\begin{align*}
s^2&=\frac{\sum\limits_{i=1}^n(x_i-\overline{x})^2}{n}\\
&=\frac{\sum\limits_{i=1}^n(x_i^2-2x_i+\overline{x}^2)}{n}\\
&=\frac{(n\overline{x}^2)+(\sum\limits_{i=1}^nx_i^2)-2\overline{x}\cdot(\sum\limits_{i=1}^nx_i)}{n}\\
&=\frac{\overline{x}(n\overline{x}-2\cdot\sum\limits_{i=1}^nx_i)+(\sum\limits_{i=1}^nx_i^2)}{n}\\
&=\frac{(\sum\limits_{i=1}^nx_i^2)-\overline{x}\cdot(\sum\limits_{i=1}^nx_i)}{n}\\
&=\frac{(\sum\limits_{i=1}^nx_i^2)-\frac{(\sum\limits_{i=1}^nx_i)^2}{n}}{n}\\
&=\frac{n\cdot(\sum\limits_{i=1}^nx_i^2)-(\sum\limits_{i=1}^nx_i)^2}{n}
\end{align*}
\]
这样就容易维护了。接下来考虑区间加时怎么更新整块的平方和,依旧推柿子:
\[\begin{align*}
\sum\limits_{i=1}^n(x_i+v)^2&=\sum\limits_{i=1}^n(x_i^2-2x_iv+v^2)\\
&=(\sum\limits_{i=1}^nx_i^2)+2v\cdot(\sum\limits_{i=1}^nx_i)+nv^2
\end{align*}
\]
然后分个块就可以做了。代码:
#include<iostream>
#include<cmath>
#define ll long long
using namespace std;
const int N=1e5+5;
const int M=320;
int n,m;
ll a[N];
namespace OIfast{
#define gc getchar()
inline unsigned read(){
unsigned n=0;char c=gc;
while(!isdigit(c))c=gc;
while(isdigit(c))n=(n<<3)+(n<<1)+(c^48),c=gc;
return n;
}
}using namespace OIfast;
namespace Math{
inline ll gcd(ll a,ll b){
return b?gcd(b,a%b):a;
}
inline ll pf(ll x){
return x*x;
}
}using namespace Math;
namespace FK{
int k,tot;
short loc[N];
int L[M],R[M];
ll s[M],ss[M],la[M];
inline void pushdown(int i){
for(int j=L[i];j<=R[i];++j)a[j]+=la[i];
return la[i]=0,void();
}
inline void pushup(int i){
s[i]=ss[i]=0;for(int j=L[i];j<=R[i];++j)s[i]+=a[j],ss[i]+=pf(a[j]);
return ;
}
inline void init(){
k=sqrt(n),tot=ceil((1.0*n)/(1.0*k));
for(int i=1;i<=tot;++i){
L[i]=(i-1)*k+1,R[i]=min(n,L[i]+k-1);
for(int j=L[i];j<=R[i];++j)loc[j]=i;
pushup(i);
}
return ;
}
inline void upd(int l,int r,ll v){
if(loc[l]==loc[r]){
pushdown(loc[l]);for(int i=l;i<=r;++i)a[i]+=v;pushup(loc[l]);
}else{
pushdown(loc[l]);for(int i=l;i<=R[loc[l]];++i)a[i]+=v;pushup(loc[l]);
pushdown(loc[r]);for(int i=L[loc[r]];i<=r;++i)a[i]+=v;pushup(loc[r]);
for(int i=loc[l]+1;i<=loc[r]-1;++i)la[i]+=v,ss[i]+=2*v*s[i]+(R[i]-L[i]+1)*pf(v),s[i]+=(R[i]-L[i]+1)*v;
}
return ;
}
inline ll qry_s(int l,int r){
ll res=0;
if(loc[l]==loc[r]){
pushdown(loc[l]);for(int i=l;i<=r;++i)res+=a[i];pushup(loc[l]);
}else{
pushdown(loc[l]);for(int i=l;i<=R[loc[l]];++i)res+=a[i];pushup(loc[l]);
pushdown(loc[r]);for(int i=L[loc[r]];i<=r;++i)res+=a[i];pushup(loc[r]);
for(int i=loc[l]+1;i<=loc[r]-1;++i)res+=s[i];
}
return res;
}
inline ll qry_ss(int l,int r){
ll res=0;
if(loc[l]==loc[r]){
pushdown(loc[l]);for(int i=l;i<=r;++i)res+=pf(a[i]);pushup(loc[l]);
}else{
pushdown(loc[l]);for(int i=l;i<=R[loc[l]];++i)res+=pf(a[i]);pushup(loc[l]);
pushdown(loc[r]);for(int i=L[loc[r]];i<=r;++i)res+=pf(a[i]);pushup(loc[r]);
for(int i=loc[l]+1;i<=loc[r]-1;++i)res+=ss[i];
}
return res;
}
#define pii pair<ll,ll>
#define mp make_pair
#define fir first
#define sec second
inline pii dx(int l,int r){
ll a=qry_s(l,r),b=r-l+1;
if(!a)return mp(0,1);
ll g=gcd(a,b);
return mp(a/g,b/g);
}
inline pii fc(int l,int r){
ll a=(r-l+1)*qry_ss(l,r)-pf(qry_s(l,r)),b=pf(r-l+1);
if(!a)return mp(0,1);
ll g=gcd(a,b);
return mp(a/g,b/g);
}
}using namespace FK;
inline void work(){
int op=read(),l=read(),r=read();
if(1==2)puts("wow");
else if(op==1){ll d=read();upd(l,r,d);}
else if(op==2){pii tmp=dx(l,r);printf("%lld/%lld\n",tmp.fir,tmp.sec);}
else if(op==3){pii tmp=fc(l,r);printf("%lld/%lld\n",tmp.fir,tmp.sec);}
return ;
}
signed main(){
n=read(),m=read();for(int i=1;i<=n;++i)a[i]=read();
init();while(m--)work();
return 0;
}
提交记录。

浙公网安备 33010602011771号