洛谷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=1nai
并定义它的方差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=l∑rai)÷(r−l+1)
d = ∑ i = l r ( a i − a a ) 2 d=\sum_{i=l}^{r} (a_{i}-aa)^{2} d=i=l∑r(ai−aa)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=l∑r(ai2−2ai⋅aa+aa2)=(r−l+1)aa2−2aai=l∑rai+i=l∑rai2
所以其实是一个区间和和区间平方和。
用树状数组维护。
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++!!!
总结
水题,题解里说的,我拿来水博客了。