zoukankan      html  css  js  c++  java
  • [洛谷5142]区间方差 题解

    前言

    这是一道线段树板子题。

    题解

    我们观察这个式子

    [avg=frac{1}{n}sum_{i=1}^n a_i ]

    [d=frac{1}{n}sum_{i=1}^n (a_i-avg)^2 ]

    我们把它展开变成

    [d=frac{1}{n}sum_{i=1}^n (a_i^2-2 imes a_i imes avg - avg^2) ]

    提出常数项得

    [d=frac{1}{n}(sum_{i=1}^n a_i^2-2 imes avg imes sum_{i=1}^n a_i + n imes avg^2) ]

    那么我们开两棵线段树,一棵维护(a_i)的和,一棵维护(a_i^2)的和,在加一个乘法逆元即可。
    结果蒟蒻博主还WA了一次,原因是取模不勤

    代码

    两棵线段树放在一起处理,十分方便。
    逆元按照巨佬的说法,用了快速幂(再见拓欧)。

    #include <cstdio>
    #define ll long long
    
    ll s[400005], s2[400005];
    const ll MOD = 1e9 + 7;
    
    ll read(){
    	ll x = 0; int zf = 1; char ch = ' ';
    	while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
    	if (ch == '-') zf = -1, ch = getchar();
    	while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x * zf;
    }
    
    ll getInv(ll x){
    	ll res = 1;
    	for (int y = MOD - 2; y; y >>= 1, x = (x * x) % MOD)
    		if (y & 1)
    			(res *= x) %= MOD;
    	return res;
    }
    
    void build(int pos, int l, int r){
    	if (l == r){
    		s[pos] = read(); s2[pos] = (s[pos] * s[pos]) % MOD;
    		return ;
    	}
    	int mid = (l + r) >> 1;
    	build(pos << 1, l, mid);
    	build(pos << 1 | 1, mid + 1, r);
    	s[pos] = s[pos << 1] + s[pos << 1 | 1];
    	s2[pos] = s2[pos << 1] + s2[pos << 1 | 1];
    }
    
    ll query(int pos, int l, int r, int x, int y){
    	if (x <= l && r <= y)
    		return s[pos];
    	ll ans = 0; int mid = (l + r) >> 1;
    	if (x <= mid)
    		ans += query(pos << 1, l, mid, x, y);
    	if (mid < y)
    		(ans += query(pos << 1 | 1, mid + 1, r, x, y)) %= MOD;
    	return ans;
    }
    
    ll query2(int pos, int l, int r, int x, int y){
    	if (x <= l && r <= y)
    		return s2[pos];
    	ll ans = 0; int mid = (l + r) >> 1;
    	if (x <= mid)
    		ans += query2(pos << 1, l, mid, x, y);
    	if (mid < y)
    		(ans += query2(pos << 1 | 1, mid + 1, r, x, y)) %= MOD;
    	return ans;
    }
    
    void modify(int pos, int l, int r, int x, ll val){
    	if (l == r){
    		s[pos] = val, s2[pos] = (val * val) % MOD;
    		return ;
    	}
    	int mid = (l + r) >> 1;
    	if (x <= mid)
    		modify(pos << 1, l, mid, x, val);
    	else if (mid < x)
    		modify(pos << 1 | 1, mid + 1, r, x, val);
    	s[pos] = (s[pos << 1] + s[pos << 1 | 1]) % MOD;
    	s2[pos] = (s2[pos << 1] + s2[pos << 1 | 1]) % MOD;
    }
    
    int main(){
    	int n = read(), m = read();
    	build(1, 1, n); ll c, a, b;
    	while (m--){
    		c = read(), a = read(), b = read();
    		if (c == 1)
    			modify(1, 1, n, a, b);
    		else if (c == 2){
    			ll ans2 = query2(1, 1, n, a, b), ans = query(1, 1, n, a, b);
    			ll avg = (ans * getInv(b - a + 1)) % MOD;
    			ll res = (((ans2 - (avg * ans * 2ll % MOD) + ((((avg * avg) % MOD) * (b - a + 1)) % MOD)) % MOD * getInv(b - a + 1))) % MOD;
    			while (res < 0) res += MOD;
    			printf("%lld
    ", res);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    第9章 线程编程(7)_线程同步4:信号量
    第9章 线程编程(6)_线程同步3:条件变量
    第9章 线程编程(5)_线程同步2:读写锁
    第9章 线程编程(4)_线程同步1:互斥锁
    第9章 线程编程(3)_线程清理和控制函数
    第9章 线程编程(2)_线程创建和终止
    第9章 线程编程(1)_线程概念和线程标识
    第8章 信号(6)_贯穿案例2:mini shell(3)
    第8章 信号(5)_信号集和信号屏蔽
    第8章 信号(4)_中断的系统调用和函数可重入性
  • 原文地址:https://www.cnblogs.com/linzhengmin/p/11128621.html
Copyright © 2011-2022 走看看