CF2018F Speedbreaker Counting
题目大意:
对于一个长度为 \(n\) 的数组 \(a\),满足 \(1 \le a_{i} \le n\),定义 \(f_{i} = 0/1\) 表示从 \(i\) 这个点出发,一开始占领 \(i\) 点,每一个时刻可以选择往左或者往右扩张,如果存在一种方案使得每个点的被攻占的时间不超过 \(a_{i}\),那么 \(f_{i} = 1\),否则 \(f_{i} = 0\)。
然后定义 \(g = \text{popcount}(f)\)。
现在给定 \(n\),而 \(a\) 未知,你要对于每个 \(k\),求所有可能的 \(a\),求 \(\text{popcount}(a) = k\) 的le 3000个数。
\(n \le 3000\)
解题思路:
有策略性的东西,显然要去分析他的策略是什么。
这种两个方向的东西,就像选左右括号去匹配一样,我们尽可能地先选一边,如果另一边比较紧急那么就跑去救火。
这题也一样,我们可以先能往右选就往右选,但如果左边有一个再不往左跑就不合法的就必须往左跑。
有了策略,我们就要开始判定一个位置什么时候合法,首先我们刚刚只是 “紧急情况”,但如果一个点刚出生就来不及了,那么就寄寄了。
所以一个点成功的必要条件是在 \(\cap_{i} [i - a_{i} + 1 \sim i + a_{i} - 1]\)。
然后考虑很难找到一个充要的条件,但我们发现这个区间内的点是 “完全等价” 的,因为 \(l,r\) 一开始一定会 “对冲”,就是 \(l\) 向右扩张, \(r\) 向左扩张,不然 \(l-1,r+1\) 也就合法了。
所以只要答案大于 \(0\) 就一定为这个集合的大小。
并且他们一开始会占领整个的区间!!!
那么设 \(dp_{l,r,0/1}\) 表示已经确定并占领了 \(l \sim r\) 这段区间,现在左边有没有限制这个区间向左扩张的。
转移的时候分讨一下是往左还是往右,如果往左还要讨论一下 \(l - 1\) 是不是唯一一个限制他们向左扩张的点。
这样对于每个 \(k\) 都跑一遍,就是 \(O(n^3)\) 的。
而优化也是套路的,因为你会发现每次都是求的 \(dp_{1,n,0/1}\) 的值,那么可以倒推一下每个状态对他的贡献。
至于恰好的事,随便容斥一下就行了。
\(O(n^2)\)。

浙公网安备 33010602011771号