GZOI2024 Day1 T3 coin

coin(GZOI2024 Day1 T3)

题目大意

给你 \(n\) 个硬币,每个硬币有属性 \(a_i,b_i,p_i\),表示有 \(p_i\) 的概率值为 \(a_i\),有 \(1-p_i\) 的概率值为 \(b_i\)。所有的 \(a_i\) 所有的 \(b_i\) 均不同。有 \(q\) 次询问,询问有两种:

  1. 给定 \(l,r,k\),问 \([l,r]\) 的硬币值都 \(<\)\(k\) 个硬币的值的概率是多少。
  2. 给定 \(x,a,b,p\),把第 \(x\) 个硬币修改成 \(a,b,p\)

做法1 线段树

假设 \(a_i<b_i\),可以把第 \(k\) 的硬币分别计算 \(a_k,b_k\),算两次,答案按照概率相加。设第 \(k\) 个硬币的值为 \(x\),在 \(i\in[l,r]\)\(i\not =k\),若:

  • 存在 \(x<a_i\),则 \(ans=0\)。(无论怎么去取,第 \(i\) 个硬币都比 \(x\) 大)
  • \(b_i<x \Rightarrow ans\times 1\)(无论怎么去取,第 \(i\) 个硬币都比 \(x\) 小)
  • \(a_i<x<b_i \Rightarrow ans\times p_i\)

所以如果 \([l,r]\) 存在 \(x<a_i\) 答案为 \(0\),这个很好判断。

否则答案是 \(\prod_{i=l}^r p_i[x<b_i]\)

维护一颗线段树,每个节点表示一个区间。答案就是 \(\log\) 个区间的答案相加。

每个区间我们要取 \(b_i>x\) 的答案,考虑对线段树每个节点再维护一个数组,把 \(b_i\) 排序。做个前缀或者后缀积,询问时二分一下。不考虑修改时间复杂度 \(O(n\log^2n)\),空间 \(O(n\log n)\)

修改时是单点修改。显然数组不好单点删除和插入,同时维护有序和前或后缀积。

考虑到每次修改只会涉及到线段树上 \(\log\) 个节点,我们把修改离线,加入那 \(\log\) 个数组的下标,要进行单点修改和前后缀积的操作,维护树状数组即可,空间仍然是 \(O(n\log n)\) 的,时间仍然是 \(O(n\log^2n)\)

注意树状数组还需维护有多少个 \(0\),没有 \(0\) 才能计入答案。

总的来说,就是线段树套树状数组,离线询问离散化,优化空间。

做法2 分块

\(0\) 是好维护的,这里忽略不讲。

每个块按 \(b\) 排序,维护前缀积。

对于询问,整块进行二分定位,乘起来,散块暴力合并,时间 \(O(T+\frac{n}{T}\log T)\)

对于修改,重构块,时间复杂度是 \(O(T)\)

总的时间复杂度是 \(O(q(T+\frac{n}{T}\log T))=O(q(T+\frac{n}{T}\log N))\ge O(q\sqrt{N\log N})\)

\(T=\sqrt{N \log N}\) 时,时间复杂度最小,为 \(O(q\sqrt{N\log N})\)

感觉分块更好写

精度的坑

虽然输入只有四位小数,但是可能因为二进制存小数位的问题,在输入时就会掉精度,如 \(0.0003\) 会变成 \(0.0002999 \dots 9997\)。解决办法时用 \(char\) 输入,或者乘上 \(10000\) 后四舍五入一下。

另一个比较常识的坑是小数按整型输出会直接抹掉小数位,不是四舍五入。

posted @ 2024-09-09 09:26  liyixin  阅读(34)  评论(0编辑  收藏  举报