#线段树,排列组合#洛谷 6108 [Ynoi2009] rprsvq

题目链接


分析

维护区间和以及区间平方和都比较简单,考虑答案是什么,根据方差公式的变形。

\[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;
} 
posted @ 2021-10-20 07:37  lemondinosaur  阅读(25)  评论(0编辑  收藏  举报