题解:P16799 [蓝桥杯 2026 国 B] 实验数据
GreenMelon · · 题解
题目很清晰,就是说让你求出区间方差。
考虑将方差公式展开来。过程如下:
其中
注意到本题为单点修改区间查询,使用树状数组即可完成此题。设置两个树状数组,一个记录区间和一个记录区间平方和。
对于中间的除法运算(如求平均数),需将除法转换为逆元。
::::success[AC Code]
#include<bits/stdc++.h>
using namespace std;
#define N 300005
#define mod 998244353
#define int long long
#define pii pair<int, int>
#define endl "\n"
#define max(x, y) (x>y?x:y)
#define min(x, y) (x<y?x:y)
int n, m, a[N];
class GreenMelon{
private:
int s[N];
inline int lowbit(int x){ return x&(-x); }
public:
inline void add(int k, int x){
x%=mod;
for(int i=k;i<=n;i+=lowbit(i)){
s[i] = (s[i]+x)%mod;
}
}
inline int query(int k){
int ans=0;
for(int i=k;i;i-=lowbit(i)){
ans = (ans+s[i])%mod;
}
return ans;
}
} sum, powsum;
inline int poww(int a, int b, int p){
int ans=1;
while(b){
if(b&1){
ans=ans*a%p;
}
a=a*a%p;
b>>=1;
}
return ans%p;
}
main(){
#ifdef Greenmelon
freopen("", "r", stdin);
freopen("", "w", stdout);
#endif
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
sum.add(i, a[i]);
powsum.add(i, a[i]*a[i]%mod);
}
for(int i=1;i<=m;i++){
int op, x, y;
cin>>op>>x>>y;
if(op==1){
int s=(sum.query(y)-sum.query(x-1)+mod)%mod;
int pows=(powsum.query(y)-powsum.query(x-1)+mod)%mod;
int len=y-x+1;
int bar=s*poww(len, mod-2, mod)%mod;
int var=(pows-2*bar%mod*s%mod+mod)%mod;
var=(var+bar*bar%mod*len%mod)%mod;
cout<<bar%mod<<" "<<var%mod<<endl;
}
else{
y%=mod;
sum.add(x, (y-a[x]+mod)%mod);
powsum.add(x, (y*y%mod-a[x]*a[x]%mod+mod)%mod);
a[x]=y;
}
}
}
::::