• 2022.8.16 模拟赛


    T1

      究极大水题,一眼背包板子,然后就做完了。

    T2

    40pts

      直接考虑树形 d p dp dp,令 f x , 0 f_{x, 0} fx,0 表示 x x x 的子树且不选 x x x 的答案, f x , 1 f_{x, 1} fx,1 表示 x x x 的子树且选 x x x 的答案,那么:

    f x , 1 = ∏ y ∈ s o n ( x ) f y , 0 f x , 0 = ∏ y ∈ s o n ( x ) max ⁡ { f y , 1 , f y , 0 }

    fx,1=yson(x)fy,0fx,0=yson(x)max{fy,1,fy,0}" role="presentation" style="position: relative;">fx,1=yson(x)fy,0fx,0=yson(x)max{fy,1,fy,0}
    fx,1=fx,0=yson(x)fy,0yson(x)max{fy,1,fy,0}

      然后发现如果这样搞的话需要边取模边比大小,那么正确性就不能保证,所以要整个乘完之后再取模。但是这样显然就会爆 l o n g    l o n g long \; long longlong,甚至会爆 __ i n t 128 int128 int128,所以我们要想想解决方案。

    100pts

      首先考虑高精,算了一下发现存不下,空间爆炸了。

      然后考虑记录一个数被取模的次数,然后发现只能比较到 1 e 36 1e36 1e36 就是极限了,但是我们的数据会到达 1 e ( 1.8 e 6 ) 1e(1.8e6) 1e(1.8e6),所以还是不行。

      于是这里就要用到一种比较聪明的做法,就是对点权取对数,这样要算 x y xy xy 就可以转变成 log ⁡ x + log ⁡ y \log x + \log y logx+logy,这样就不用担心爆 l o n g    l o n g long \; long longlong 的问题了。

      然后就做完了。

    T3

    10pts

      最暴力的暴力,按照题目描述模拟就好了。

    25pts

      题解上说的 25 p t s 25pts 25pts O ( n 2 log ⁡ n ) O(n^2 \log n) O(n2logn) 的做法,但是这里我有 O ( n 2 ) O(n^2) O(n2) 的做法qwq。

      还是沿用暴力的思路,枚举区间长度然后判断这个区间长度可不可行。纯暴力的话判断区间长度是否可行的复杂度就是 O ( n 2 ) O(n^2) O(n2) 的,所以我们考了优化这个算法。

      我们发现,在暴力算法中我们在维护的一个东西就很想某一个算法的板子,没错,就是莫队。我们就在维护每一种数字的数量(弄一个桶),所以我们现在也考虑 O ( 1 ) O(1) O(1) 移动区间端点。

      记录一个 c n t cnt cnt 表示当前不满足条件的数字的个数,然后桶在移动端点的时候显然是可以 O ( 1 ) O(1) O(1) 计算的,那么我们考虑对于一个端点产生的贡献,分三种情况:

    1. 移动一个端点后,是的某一个数字一开始符合条件,移动后不符合条件,那么此时 c n t + + cnt++ cnt++
    2. 移动一个端点后,是的某一个数字一开始不符合条件,移动后符合条件,那么此时 c n t − − cnt-- cnt
    3. 其他情况 c n t cnt cnt 不变。

      于是我们可以暴力扫一遍每一个长度的第一个区间,然后 O ( 1 ) O(1) O(1) 向后扩展,并判断 c n t cnt cnt 是否等于 0 0 0。这个做法复杂度就是 O ( n 2 ) O(n^2) O(n2) 的了。

    ?pts

      首先 b b b 是单调不增的,也就是说大区间的约束没有小区间的严格,所以我们考虑从大区间加一些限制转到小区间。

      我们发现,如果一个大区间中的某一个数字 p p p 会使得这个区间不合法,那么所有包含这个数字 p p p 的小区间都是不合法的,所以我们考虑找出大区间中所有这样的 p p p,并把这些点删掉,然后大区间就变成了许多的小区间。这样就可以分治处理。

      但是这样的复杂度就有一点玄学了(据说是 O ( n n ) O(n \sqrt n) O(nn ) 的),随便搞一搞就能知道应该过不了 1 e 6 1e6 1e6,所以还要继续优化。

    100pts

      首先每一次都找出出现次数不满足限制的所有数字这就是 O ( n ) O(n) O(n) 的,所以我们考虑每次只找到一个点然后一这个点为界拆分成两个区间,然后递归处理,这样不会影响正确性但是由于随便找一个点的位置是不均等的,所以时间会可能被卡成 O ( n 2 ) O(n^2) O(n2),所以我们就要用到启发式合并的思想。

      想象递归向上合并,我们每次取小的合并,复杂度就一定是 O ( n log ⁡ n ) O(n \log n) O(nlogn) 的,所以我们也沿用这种思路,看看能不能做到每次找到点 p p p 并分成两段之后只用 O ( 较小段 ) O(较小段) O(较小段) 的时间处理问题。

      于是我们考虑当前区间为 [ l , r ] [l, r] [l,r] 并且我们拥有当前区间的桶,然后考虑怎样处理,处理的步骤如下:

    1. 考虑从某一段返回时,清空这一段对桶的贡献。
    2. 首先我们可以从两头同时向中间走,每次查询桶里的值查到不满足限制的就 b r e a k break break,这样找到 p p p 的时间就是 O ( 较小段 ) O(较小段) O(较小段)
    3. 然后考虑分成两段,并找到较小的一段,一个循环暴力删掉较小段对桶的贡献,这样桶里面就只装的是较大段的贡献了,现在就可以递归进入较大段,时间仍然是 O ( 较小段 ) O(较小段) O(较小段)
    4. 然后从较大段回溯回来的时候因为有第一步,所以较大段对桶的贡献已经被清除了,所以现在只需要把较小段的贡献暴力加回来就能进入较小段递归了,时间还是 O ( 较小段 ) O(较小段) O(较小段)

      这样一来,总体的时间复杂度就和启发式合并是相同的了,那么这道题就愉快的切掉了。

  • 相关阅读:
    【Hello Algorithm】暴力递归到动态规划(二)
    软考中级和高级,有什么区别?
    初入社会的测试如何去判断一个公司值不值得继续待下去?
    数据库-基础篇-SQL-DML(数据操作语言)
    Elasticsearch索引分片的数量及大小分配策略
    Visual Studio 错误CS0006:未能找到元数据文件踩坑记录
    我的区块链笔记
    Packet Tracer – 比较 RIP 和 EIGRP 路径选择
    【C++】多态学习
    Kotlin委托
  • 原文地址:https://blog.csdn.net/ID246783/article/details/126363923