CF1903D:Maximum And Queries 题解
D:
题意:给你一个数列a,Q个独立询问,每次操作给一个数加一,k次操作后最大化数列a的与值。
Solution:
因为是最大化与值,那高位和低位就不冲突了,贪心看每一位能不能成为答案的一部分。
我们用res表示已经确定成为答案的高位和,当我们考虑第 i 位能不能加入答案时,我们计算三种数的花费:
1:这个数为了让高位成为答案,低位已经被磨平了棱角(悲),那么花费就是 \(2^i\) 。
2:这个数res的每一位它都有,也就是说低位还在,但是它第 i 位是0,需要补齐到第 i 位,那么低位就要被磨平了,花费是 \(2^i-sum[i]\),\(sum[i]\) 是它低 i 位的和。
3:这个数很坚强,res的每一位它都有,第 i 位也有,不用管它,花费为 0。
第一种数从何而来,就是从第二种来,用 \(num\) 表示第一种数的个数,每一位如果被确定为答案,就把第二种数的数量加给 num。
发现第二种数与res有关,哪些高位被确定成答案,直接影响每一个数是否被磨平。我们设 \(f[res][i]\) 表示当前答案为 \(res\) 时高位它都有,但是第 i 位为零的数的数量,\(g[res][i]\) 表示这些数后 i 位的和。那么第二种数的花费就是:\(2^i*f[res][i]-g[res][i]\)。
这一位计算完成后,\(num+=f[res][i]\)。
当你以为设出状态来这题就结束时,却发现 f 数组和 g 数组怎么算成为了这道题的难点。其实也不难,只需要掌握一个小小的科技,就是子集DP。一看就懂的子集DP
对于每一个数,查看其为0的数位 i,res 作为 i 的高位的子集时,更新 f 数组和 g 数组,也就是说高位是超集,贡献向子集传递(高维后缀和)。
这题我们枚举res位数是从20开始向下的,但是答案可能很大,需要把那些答案大于20位的询问直接处理掉。

浙公网安备 33010602011771号