数论+计数+dp+贪心+堆
A.gcd
考虑到前缀 值互不相同的只有 个,同时他们也是单调不升的。
所以我们可以暴力遍历所有的前缀 ,用双向链表删去那些与前面值相同的元素。
在删的时候注意把数量累加就好了。
B.or_and
差一点想出做法
首先,可以分位考虑,考虑每一位被统计了多少次。
我们知道,二进制中的一位被统计,当且仅当这一位在两个数中至少有一个 。
我们可以统计出 的数中这一位是 的个数 , 中的个数 。
那么简单容斥一下,这一位的贡献就是 ,我们重复计算了两位都是 的部分。
问题传化为了求 ,。
分类讨论一下:
- 如果当前这一位是 ,这一位前面的填法是唯一的,而后面可以按照原数填,也可以随便填。
- 如果当前这一位是 ,我必须要把它变为 ,考虑从上面借一位,后面随便填。注意上面的方案数要加 。
C.middle
好题。
首先将 数组排序,有如下性质:
- ,根据中位数的定义显然。
- 任意 ,不存在 或 ,考虑中位数每次向外拓展两个单位,不会一下比两个数都小。
根据这两条性质,我们可以进行 。
发现这些性质都是越向后越紧的,所以我们可以考虑从后向前 ,维护哪些数可以成为中位数。
设 表示已经确定了 ,备选集合中 的数量为 , 的数量为 的方案数。
考虑由 ,增加的两个数 和 (性质一),如果它们不等于 ,那么备选集合将扩大。
我们转移的决策就是在枚举 选什么。
- 选了和 相同的数:备选集合没有改变,直接 。
- 选了小于 的数,那么就枚举这个数在集合中的排名 。显然,排名在 之间的都没有用(性质二),而 因为比 大,归到了后面那类:。
- 选了大于 的数,同理:。
D.beautiful
保证前面的合法,考虑新加两个位置的贡献。
为了保证合法,最后一个位置肯定是右括号,我们来讨论前面填什么。
-
填左括号,直接匹配。
-
填右括号,为了合法,我们要把前面的一个右括号变为左括号,贪心地想,自然取代价最小的,即 最小。
所以开个小根堆,维护前面右括号中 的最小值即可。