分析
维护区间和以及区间平方和都比较简单,考虑答案是什么,根据方差公式的变形。
[ans=frac{sum_{j=1}^na_j^2}{n}-frac{(sum_{j=1}^na_j)^2}{n^2}
]
要搭配上排列组合,但是后面这一坨很难求,考虑把二次项拆开,真正的答案就是
[ans=sum_{i=2}^nfrac{(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
eq 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}^nfrac{(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}^nfrac{C(n-2,i-2)}{i^2}=sum_{i=2}^nfrac{C(n,i)C(i,2)}{C(n,2)i^2}=frac{1}{n(n-1)}sum_{i=2}^nfrac{C(n,i)(i-1)}{i}
]
也就是
[frac{1}{n(n-1)}(sum_{i=2}^nC(n,i)-sum_{i=2}^nfrac{C(n,i)}{i})=frac{1}{n(n-1)}(2^n-1-sum_{i=1}^nfrac{C(n,i)}{i})
]
后面这一坨比较难求,可以求导之后再积分,设 (f(x)=sum_{i=1}^nfrac{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^1frac{(x+1)^n-1}{x}{
m d}x=int_1^2frac{y^n-1}{y-1}{
m d}y=int_1^2sum_{i=0}^{n-1}y^i{
m d}y
]
最后答案也就是
[frac{n(s^2_n)-(s_n)^2}{n(n-1)}(2^n-1-sum_{i=1}^nfrac{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;
}