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 } \begin{aligned} f_{x, 1} = & \prod_{y \in son(x)}f_{y, 0} \\ f_{x, 0} = & \prod_{y \in son(x)} \max \{ f_{y, 1}, f_{y, 0} \} \end{aligned} 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(较小段)

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值