(树状数组+逆元)洛谷P5142 区间方差

洛谷P5142 区间方差

(^ w ^)

题目背景

出题人并没有能力写有趣的题面……
题目描述

对于一个长度为n的序列a1,a2,a3⋯ana_1,a_2,a_3\cdots a_na1​,a2​,a3​⋯an​,我们定义它的平均数a为:

a=1n∑i=1naia=\frac{1}{n}\sum_{i=1}^{n}a_ia=n

1​∑i=1n​ai​

并定义它的方差d为:

d=1n∑i=1n(ai−a)2d=\frac{1}{n}\sum_{i=1}{n}(a_i-a)2d=n

1​∑i=1n​(ai​−a)2

现在给定一个长度为n的序列b1,b2⋯bnb_1,b_2\cdots b_nb1​,b2​⋯bn​。你需要支持两种操作。每种操作的格式为c x y。

若c=1,为修改操作,代表将bxb_xbx​赋值为y。

若c=2,为查询操作,代表查询bxb_xbx​到byb_yby​的方差。

为了避免浮点数误差,请以分数取模形式输出结果(对1000000007(109+710^9+7109+7)取模)。如果不知道什么是分数取模,请看下文。

对于一个正整数a,如果a÷M=p⋯ra\div M=p\cdots ra÷M=p⋯r,则称a模M为r。记为a≡r(mod M)a\equiv r(\mod ~M)a≡r(mod M)或者a%M=ra%M=ra%M=r。

对于一个正整数a,如果存在正整数b,使得a×b≡1(mod M)a\times b\equiv 1(\mod~M)a×b≡1(mod M),则称b为a的逆元,记为b=rev(a)b=rev(a)b=rev(a)。此题我们保证逆元一定存在。

对于一个分数ab\frac{a}{b}b

a​,其取模表示为:a×rev(b)%Ma\times rev(b)%Ma×rev(b)%M。

在此题中,M=1000000007(109+710^9+7109+7)。
输入输出格式
输入格式:

第一行两个数n,m,代表序列b的长度为n,有m个操作。

第二行n个整数bib_ibi​,表示序列b的初始值。

下面有m行整数,每行格式为c a b,含义如上文所示。保证所有操作合法。

输出格式:

对于每个操作2,输出一行。

输入输出样例
输入样例#1: 复制

4 8
0 0 0 0
1 1 1
1 2 2
1 3 3
1 4 4
2 1 1
2 1 2
2 1 3
2 1 4

输出样例#1: 复制

0
250000002
666666672
250000003

题解

反正没什么好说的,题目很好懂。我们稍微动一下笔可得到以下结论。
设:
原数组为   a i \ a_{i}  ai
平均数为   a a \ aa  aa
方差为   d \ d  d
区间为   [ l , r ] \ [l,r]  [l,r]

a a = ( ∑ i = l r a i ) ÷ ( r − l + 1 ) aa=(\sum_{i=l}^{r} a_{i}) \div (r-l+1) aa=(i=lrai)÷(rl+1)

d = ∑ i = l r ( a i − a a ) 2 d=\sum_{i=l}^{r} (a_{i}-aa)^{2} d=i=lr(aiaa)2

化简一下得

d = ∑ i = l r ( a i 2 − 2 a i ⋅ a a + a a 2 ) = ( r − l + 1 ) a a 2 − 2 a a ∑ i = l r a i + ∑ i = l r a i 2 d=\sum_{i=l}^{r}(a_{i}^{2}-2a_{i} \cdot aa+aa^{2})=(r-l+1)aa^{2}-2aa\sum_{i=l}^{r}a_{i}+\sum_{i=l}^{r}a_{i}^{2} d=i=lr(ai22aiaa+aa2)=(rl+1)aa22aai=lrai+i=lrai2

所以其实是一个区间和和区间平方和。
用树状数组维护。
AC代码。复杂度 O(   n l o g 2 n + m l o g 2 2 n \ nlog_{2}n+mlog_{2}^{2}n  nlog2n+mlog22n)

#include<bits/stdc++.h>
using namespace std;
long long n,m,c[100100],cs[100100];
const long long p=1000000007;
inline long long read()
{
    long long s=0,w=0;
    char ch=0;
    while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
    while(isdigit(ch)){s=(s<<3)+(s<<1)+(ch^0x30);ch=getchar();}
    return w ? -s : s;
}
inline long long lowbit(long long x)
{
	return x&(-x);
}
inline long long quc(long long i)
{
    long long res=0;
    while(i)
	{
        res=(res+c[i])%p;
        i-=lowbit(i);
    }
    return res;
}
inline long long qucs(long long i)
{
    long long res=0;
    while(i)
	{
        res=(res+cs[i])%p;
        i-=lowbit(i);
    }
    return res;
}
inline long long inv(long long x)
{
    if(x==1) return 1;
    if(x<1) return 0;
    return (p-p/x)*inv(p%x)%p;
}
inline void change(long long i,long long k)
{
    long long d=k-(quc(i)-quc(i-1));
    long long t=i;
    while(t<=n)
	{
        c[t]=(c[t]+d)%p;
        t+=lowbit(t);
    }
    d=k*k-(qucs(i)-qucs(i-1));
    t=i;
    while(t<=n)
	{
        cs[t]=(cs[t]+d)%p;
        t+=lowbit(t);
    }
}
int main()
{
	memset(c,0,sizeof(c));
	memset(cs,0,sizeof(cs));
	n=read();
	m=read();
	long long i=1;
	while(i<=n)
	{
		int a=read();
		if(a!=0) change(i,a);
		++i;
	}
	long long op;
	while(m--)
	{
		op=read();
		if(op^1)
		{
			long long l,r;
			l=read();
			r=read();
			if(l==r) printf("0\n");
            else
            {
            	long long av,inve,ans=0;
            	inve=inv(r-l+1);
            	av=(quc(r)-quc(l-1))*inve%p;
            	ans=((qucs(r)-qucs(l-1))%p-(av<<1)*(quc(r)-quc(l-1))%p)*inve%p;
            	ans=((ans+av*av%p)%p+p)%p;
            	printf("%d\n",ans);
        	}
        }
		else
		{
			long long a,b;
			a=read();
			b=read();
			change(a,b);
		}
	}
	return 0;
}
/*
1996年:东方灵异传(TOH1)
1997年:东方封魔录(TOH2)
1997年:东方梦时空(TOH3)
1998年:东方幻想乡(TOH4)
1998年:东方怪绮谈(TOH5)
2002年:东方红魔乡(TOH6)
2003年:东方妖妖梦(TOH7)
2004年:东方萃梦想(TOH7.5)
2004年:东方永夜抄(TOH8)
2005年:东方花映冢(TOH9)
2005年:东方文花帖(TOH9.5)
2007年:东方风神录(TOH10)
2008年:东方绯想天(TOH10.5)
2008年:东方地灵殿(TOH11)
2009年:东方星莲船(TOH12)
2009年:东方非想天则(TOH12.3)
2010年:东方文花帖DS(TOH12.5)
2010年:东方三月精(TOH12.8)
2011年:东方神灵庙(TOH13)
2013年:东方心绮楼(TOH13.5)
2013年:东方辉针城(TOH14)
2014年:弹幕天邪鬼(TOH14.3)
2014年:东方深秘录(TOH14.5)
2015年:东方绀珠传(TOH15)
2017年:东方凭依华(TOH15.5)
2017年:东方天空璋(TOH16)
*/
//RP++!!!

总结

水题,题解里说的,我拿来水博客了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值