分析
维护区间和以及区间平方和都比较简单,考虑答案是什么,根据方差公式的变形。
\[ans=\frac{\sum_{j=1}^na_j^2}{n}-\frac{(\sum_{j=1}^na_j)^2}{n^2} \]要搭配上排列组合,但是后面这一坨很难求,考虑把二次项拆开,真正的答案就是
\[ans=\sum_{i=2}^n\frac{(i-1)C(n-1,i-1)(\sum_{j=1}^n {a'}_{j}^2)}{i^2}-\frac{C(n-2,i-2)\sum_{j_0\neq j_1}a'_{j0}a'_{j1}}{i^2} \]设 \(s^2_n=\sum_{i=1}^n a_j^2,(s_n)^2=(\sum_{i=1}^n a_i)^2\)
把前面这个组合数转换一下就是
\[ans=\sum_{i=2}^n\frac{(n-1)C(n-2,i-2)s^2_n}{i^2}-\frac{C(n-2,i-2)((s_n)^2-s^2_n)}{i^2}=ans=(n(s^2_n)-(s_n)^2)\sum_{i=2}^n \frac{C(n-2,i-2)}{i^2} \]关键是后面这一坨,因为 \(C(n-2,i-2)C(n,2)=C(n,i)C(i,2)\),所以
\[\sum_{i=2}^n\frac{C(n-2,i-2)}{i^2}=\sum_{i=2}^n\frac{C(n,i)C(i,2)}{C(n,2)i^2}=\frac{1}{n(n-1)}\sum_{i=2}^n\frac{C(n,i)(i-1)}{i} \]也就是
\[\frac{1}{n(n-1)}(\sum_{i=2}^nC(n,i)-\sum_{i=2}^n\frac{C(n,i)}{i})=\frac{1}{n(n-1)}(2^n-1-\sum_{i=1}^n\frac{C(n,i)}{i}) \]后面这一坨比较难求,可以求导之后再积分,设 \(f(x)=\sum_{i=1}^n\frac{C(n,i)x^i}{i}\)
\[f'(x)=\sum_{i=1}^nx^{i-1}C(n,i)=\frac{\sum_{i=0}^nx^iC(n,i)-1}{x}=\frac{(x+1)^n-1}{x} \]设 \(y=x+1\),积分就是
\[\int_0^1\frac{(x+1)^n-1}{x}{\rm d}x=\int_1^2\frac{y^n-1}{y-1}{\rm d}y=\int_1^2\sum_{i=0}^{n-1}y^i{\rm d}y \]最后答案也就是
\[\frac{n(s^2_n)-(s_n)^2}{n(n-1)}(2^n-1-\sum_{i=1}^n\frac{2^i-1}{i}) \]后面这一坨直接预处理即可
代码
#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=5000011,mod=998244353;
int two[N],inv[N],f[N],lazy[N<<2],n;
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
inline signed mo(int x,int y){return x+y>=mod?x+y-mod:x+y;}
struct rec{
int w0,w1;
inline rec operator +(const rec &t)const{
return (rec){mo(w0,t.w0),mo(w1,t.w1)};
}
}w[N<<2];
inline void ptag(int k,int l,int r,int z){
w[k].w1=mo(mo(w[k].w1,2ll*z*w[k].w0%mod),(r-l+1ll)*z%mod*z%mod);
w[k].w0=mo(w[k].w0,(r-l+1ll)*z%mod),lazy[k]=mo(lazy[k],z);
}
inline void pdown(int k,int l,int mid,int r){
if (lazy[k]){
ptag(k<<1,l,mid,lazy[k]);
ptag(k<<1|1,mid+1,r,lazy[k]);
lazy[k]=0;
}
}
inline void update(int k,int l,int r,int x,int y,int z){
if (l==x&&r==y){
ptag(k,l,r,z);
return;
}
rr int mid=(l+r)>>1; pdown(k,l,mid,r);
if (y<=mid) update(k<<1,l,mid,x,y,z);
else if (x>mid) update(k<<1|1,mid+1,r,x,y,z);
else update(k<<1,l,mid,x,mid,z),update(k<<1|1,mid+1,r,mid+1,y,z);
w[k]=w[k<<1]+w[k<<1|1];
}
inline rec query(int k,int l,int r,int x,int y){
if (l==x&&r==y) return w[k];
rr int mid=(l+r)>>1; pdown(k,l,mid,r);
if (y<=mid) return query(k<<1,l,mid,x,y);
else if (x>mid) return query(k<<1|1,mid+1,r,x,y);
else return query(k<<1,l,mid,x,mid)+query(k<<1|1,mid+1,r,mid+1,y);
}
signed main(){
n=iut(),two[0]=inv[0]=inv[1]=1;
for (rr int i=2;i<=n;++i) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
for (rr int i=1;i<=n;++i) two[i]=mo(two[i-1],two[i-1]);
for (rr int i=1;i<=n;++i) f[i]=mo(f[i-1],1ll*(two[i]-1)*inv[i]%mod);
for (rr int i=1;i<=n;++i) f[i]=1ll*mo(two[i]-1,mod-f[i])*inv[i]%mod*inv[i-1]%mod;
for (rr int Q=iut();Q;--Q){
rr int opt=iut(),l=iut(),r=iut(),m=r-l+1;
if (opt==1) update(1,1,n,l,r,iut());
else{
rr rec t=query(1,1,n,l,r);
print(1ll*f[m]*mo(1ll*m*t.w1%mod,mod-1ll*t.w0*t.w0%mod)%mod),putchar(10);
}
}
return 0;
}