• #线段树,排列组合#洛谷 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}^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;
    } 
    
  • 相关阅读:
    【程序员面试宝典】第五章 程序设计基本概念
    win7打开或关闭windows功能 提示“出现错误,并非所有的功能被更改”,管理员权限惹的祸
    堆排序
    目态与管态的概念
    循环不变式的概念
    getchar()函数的返回值赋给char型,用if(ch=getchar() != EOF)测试,输入ctrl+z同样可以结束循环的分析
    java算法 -- 冒泡排序
    Java算法 -- 二分查找
    Sql知识点总结
    java实现 链表反转
  • 原文地址:https://www.cnblogs.com/Spare-No-Effort/p/15427246.html
Copyright © 2020-2023  润新知