
P5142 区间方差 题解
发布日期:2021-05-09 00:16:14
浏览次数:18
分类:博客文章
本文共 3408 字,大约阅读时间需要 11 分钟。
简述题意
给一段序列,支持区间求方差,单点修改
前置芝士
- 线段树/树状数组/分块
- 逆元
- 推式子
Solution
题目中已经给出了方差的求法,我们这里设 \(len\) 表示要求的区间长度:
\[d = \frac{1}{len} \sum_{i = l}^{r} (a_i - \overline{a})^2\]
看上去不好维护,让我们化简试试:
\[d = \frac{1}{len} \sum_{i = l}^{r} (a_i^2 - 2 \cdot a_i \cdot \overline{a} + \overline{a}^2)\]
直接利用乘法分配律将其分开:
\[d = \frac{1}{len} \sum_{i = l}^{r} a_i^2 - \frac{1}{len} \sum_{i = l}^{r} 2 \cdot a_i \cdot \overline{a} + \frac{1}{len} \sum_{i = l}^{r} \overline{a}^2\]
很简单的昂,把无关项提出来,得到:
\[d = \frac{1}{len} \sum_{i = l}^{r} a_i^2 - 2 \cdot \overline{a} \cdot \frac{1}{len} \sum_{i = l}^{r} a_i + \overline{a}^2\]
因为 \(\overline{a} = \frac{1}{len} \sum_{i = l}^{r} a_i\),所以继续化简可以得到:
\[d = \frac{1}{len} \sum_{i = l}^{r} a_i^2 - 2 \cdot \overline{a}^2 + \overline{a}^2\]
\[d = \frac{1}{len} \sum_{i = l}^{r} a_i^2 - \overline{a}^2\]
然后直接pia的一下,把线段树扔上去,维护个区间和和区间平方和,连Push_down
都不需要写,就做完了。
但是!!
我们知道方差经常是分数形式,并且这还是在模意义下。
那么求出分母的逆元就好了,具体原理见。
求逆元有两种方法(我们定义 \(a\) 的逆元为 \(a^{-1}\)):
费马小定理:\(a^{-1} = a^{p - 2} \bmod {p}\);
线性求逆元递推公式:
$inv_i = (p - \frac{p}{i}) \times inv_{p \bmod i} \bmod p $,证明的话可以看。
Tips:
- 记得开
long long
; - 取模要彻底。
剩下的看代码吧。
Code
/*Work by: Suzt_ilymicsProblem: P5142 区间方差Knowledge: 线段树Time: O(nlogn)*/#include#include #include #include #include #define LL long long#define int long long#define orz cout<<"lkp AK IOI!"< << 1) + (s << 3) + ch - '0' , ch = getchar(); return f ? -s : s;}namespace Seg{ #define lson i << 1 #define rson i << 1 | 1 struct Tree{ int val, sum; }tree[MAXN << 2]; void Push_up(int i) { // 更新 tree[i].val = (tree[lson].val + tree[rson].val) % mod; tree[i].sum = (tree[lson].sum + tree[rson].sum) % mod; } void Build(int i, int l, int r) { // 建树 if(l == r) { tree[i].val = a[l] % mod, tree[i].sum = a[l] * a[l] % mod; return ; } int mid = (l + r) >> 1; Build(lson, l, mid), Build(rson, mid + 1, r); Push_up(i); } void Modify(int i, int l, int r, int L, int R, int val_) { // 单点修改,粘的模板所以写的区间修改的形式 if(L <= l && r <= R) { tree[i].val = val_ % mod, tree[i].sum = val_ * val_ % mod; return ; } int mid = (l + r) >> 1; if(mid >= L) Modify(lson, l, mid, L, R, val_); if(mid < R) Modify(rson, mid + 1, r, L, R, val_); Push_up(i); } int Query1(int i, int l, int r, int L, int R) { // 区间和 if(L <= l && r <= R) return tree[i].val; int mid = (l + r) >> 1, ans = 0; if(mid >= L) ans += Query1(lson, l, mid, L, R); if(mid < R) ans += Query1(rson, mid + 1, r, L, R); return ans % mod; } int Query2(int i, int l, int r, int L, int R) { // 区间平方和 if(L <= l && r <= R) return tree[i].sum; int mid = (l + r) >> 1, ans = 0; if(mid >= L) ans += Query2(lson, l, mid, L, R); if(mid < R) ans += Query2(rson, mid + 1, r, L, R); return ans % mod; }}void Init() { inv[0] = inv[1] = 1; // 线性求逆元,注意初始化 for(int i = 2; i <= n; ++i) inv[i] = (mod - mod / i) * inv[mod % i] % mod;}int Quick_Pow(int x, int p, int mod) { // 快速幂(然而没用到 int res = 1; while(p) { if(p & 1) res = res * x % mod; x = x * x % mod; p >>= 1; } return res;}signed main(){ n = read(), m = read(); Init(); for(int i = 1; i <= n; ++i) a[i] = read(); Seg::Build(1, 1, n); for(int i = 1, opt, l, r; i <= m; ++i) { opt = read(), l = read(), r = read(); if(opt == 1) Seg::Modify(1, 1, n, l, l, r); else { int len = r - l + 1; int sum1 = Seg::Query1(1, 1, n, l, r) * inv[len] % mod; int sum2 = Seg::Query2(1, 1, n, l, r) * inv[len] % mod; printf("%lld\n", (sum2 - sum1 * sum1 % mod + mod) % mod); } } return 0;}
发表评论
最新留言
表示我来过!
[***.240.166.169]2025年03月30日 14时14分30秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
netcore中使用session
2021-05-09
Android 开发学习进程0.25 自定义控件
2021-05-09
多媒体文件格式全解说(下)--图片
2021-05-09
淘宝WAP版小BUG分析
2021-05-09
asp.net打印网页后自动关闭网页【无需插件】
2021-05-09
【Maven】POM基本概念
2021-05-09
【Java思考】Java 中的实参与形参之间的传递到底是值传递还是引用传递呢?
2021-05-09
【设计模式】单例模式
2021-05-09
远程触发Jenkins的Pipeline任务的并发问题处理
2021-05-09
entity framework core在独立类库下执行迁移操作
2021-05-09
Asp.Net Core 2.1+的视图缓存(响应缓存)
2021-05-09
【wp】HWS计划2021硬件安全冬令营线上选拔赛
2021-05-09
Ef+T4模板实现代码快速生成器
2021-05-09
JQuery选择器
2021-05-09
多线程之volatile关键字
2021-05-09
2.2.2原码补码移码的作用
2021-05-09
Java面试题:Servlet是线程安全的吗?
2021-05-09
Java集合总结系列2:Collection接口
2021-05-09
Linux学习总结(九)—— CentOS常用软件安装:中文输入法、Chrome
2021-05-09