A
先构造最左方案,然后能调整尽量调整即可。
时间复杂度 (O(m)).
代码: 75367082
B
显然每个二进制位是独立的,且只能有 (0) 个或 (1) 个数在该位上有值。乘起来即可。
时间复杂度 (O(log n)).
代码: 75373134
C
贪心。每次删去能删的尽量大的(不亏)。
比较好的实现方法是定义一个 solve(u)
函数,先不停地删 (u) 点直到删不下去为止,然后再递归 solve(u<<1),solve(u<<1|1)
. 没有必要比较大小,因为每个子树内删的个数是固定的。
时间复杂度 (O(2^hh)).
代码: 78094188
D
对于每一对相邻相等的元素,我们在中间画一条线,并定义线的值等于相等元素的值。于是就得到了一个新的序列,操作等价于:在新的序列上选择相邻两个元素,如果不等则一起删去,相等则留下一个。也就相当于尽量多删不等的。
不难发现最优策略:当不存在一个元素出现次数严格超过一半时一定可以一直删不同直到只剩下一个元素,否则可以让每个其他元素都和这个元素配对。策略就是如果还剩下两种或更多则取出现次数最多的和它任意一个相邻的删,否则就删相同的。
难点是如何实现:要对每个字符维护一个集合,集合中的每个元素是一个二元组,表示一对相邻不同的位置,且其中一个是该字符。使用 set
即可。
最后还要求输出方案,要找到在当前序列中的位置,树状数组+并查集维护哪些点还没被选即可。
时间复杂度 (O(n|Sigma|+nlog n)).
代码: 78207027
E
首先稍微转化一下:有 (m) 个数 (a_i),找出一个序列 (b_i) 满足 (sum^m_{i=1}b_i=K) ((m,K) 实际为输入的 (m+1,K+m+1)),对每个 (i) 找出 (b_i) 个正整数和为 (a_i),最小化所有找出的数的极差。
不难发现对于一个 (i) 最优策略一定是分配得尽量平均,即 (b_i-a_imod b_i) 个 (lfloorfrac{a_i}{b_i}
floor) 和 (a_imod b_i) 个 (lceilfrac{a_i}{b_i}
ceil). 于是就是要最小化 (max^m_{i=1}lceilfrac{a_i}{b_i}
ceil-min^m_{i=1}lfloorfrac{a_i}{b_i}
floor).
考虑求出两个值:(R) 表示 (max) 部分的最小可能值是多少,(L) 表示 (min) 部分的最大可能值是多少。这个容易直接二分得到。
可以发现如果对于每个 (i) 都存在 (b_i) 满足 (Llelfloorfrac{a_i}{b_i}
floorlelceilfrac{a_i}{b_i}
ceille R) 则一定可以在 (L) 和 (R) 的方案基础上进行调整得到总个数恰好为 (K) 的方案。即这种情况下答案为 (R-L).
但是有可能存在一些 (i) 不存在合法的 (b_i). 这时候我们求出最接近 ([L,R]) 的 (b_i),即满足 (lfloorfrac{a_i}{x}
floorlt L) 的最小的 (x) 和满足 (lceilfrac{a_i}{y}
ceilgt R) 的最小的 (y). 我们令 (a_i) 的贡献(就是参与到 (max) 和 (min) 的计算中的值)为 (x) 和 (y) 中的一者(显然它不可能同时成为 (max) 和 (min),因为它不可能既 (gt R) 又 (lt L)),那么和上面同理可证一定能调整得到一个合法方案。
于是我们的问题就转化为,有一个集合,初始时只有 (L,R) 两个数,现在有 (n) 个二元组,要从每个中挑出一个加入集合,最小化集合内的极差。直接先默认全选小的,然后从小到大每次把最小的改成选大的即可。
时间复杂度 (O(mlog m+mlog n)).
代码: 78272837