题解 CodeForces div4 压轴题合集
1. Round #640 G - Special Permutation
显然可以构造类似 1,4,2,5,3,6,9,7,10,8,... \texttt{1,4,2,5,3,6,9,7,10,8,...} 1,4,2,5,3,6,9,7,10,8,... 这样的序列循环,然后特判末 5 5 5 至 9 9 9 位。
但是有一种更简单的方法(后来想的,没写代码): 1,3,5,...,n-1,n-4,n,n-2,n-6,n-8,n-10,...,2 \texttt{1,3,5,...,n-1,n-4,n,n-2,n-6,n-8,n-10,...,2} 1,3,5,...,n-1,n-4,n,n-2,n-6,n-8,n-10,...,2
2. Round #784 H - Maximal AND
记录每个二进制位出现过几次,优先填最高位。
3. Round #790 H2 - Maximum Crossings (Hard Version)
每读入一个 a i a_i ai,用树状数组查询 [ a i , n ] [a_i,n] [ai,n] 的总和,并令第 a i a_i ai 位 + 1 +1 +1。
4. Round #799 H - Gambling
首先,题意可以转化为:
求一个区间 [ l , r ] [l,r] [l,r],一个数 a a a,使得 ∑ i = l r [ x i = a ] − ∑ i = l r [ x i ≠ a ] \sum\limits_{i=l}^r[x_i=a]-\sum\limits_{i=l}^r[x_i\neq a] i=l∑r[xi=a]−i=l∑r[xi=a] 最大。若有多组解输出任意一组。
那么首先考虑确定 a a a,那么把原序列等于 a a a 的数改为 1 1 1,不等于 a a a 的数改为 − 1 -1 −1,就变成了一个最大子段和问题,可以 O ( n ) O(n) O(n) dp 求解。
如果枚举 a a a 呢?那么这题的复杂度就是 O ( n 2 ) O(n^2) O(n2),过不了。
怎么优化呢?在 dp 求解最大子段和的过程,我们可以把连续的 − 1 -1 −1 段合并为一个数,这样只用在出现 1 1 1 的时候进行 dp。对于下标 i i i,在所有 a a a 中必然只会存在一个 1 1 1,即 a = x i a=x_i a=xi 的情况。所以我们只会 dp n n n 次。复杂度降至 O ( n ) O(n) O(n)。
设 l s i ls_i lsi 表示使 k < i , x k = x i k<i,x_k=x_i k<i,xk=xi 的最大的 k k k,则状态转移方程为:
f i = max ( f l s i − ( i − l s i − 1 ) , 0 ) + 1 f_i=\max(f_{ls_i}-(i-ls_i-1), 0)+1 fi=max(flsi−(i−lsi−1),0)+1
输出方案的话可以记录下 f i f_i fi 是从哪个地方转移过来的。具体可以参考代码。
求解
l
s
i
ls_i
lsi 也很简单,在读入时用 map
预处理一下即可,复杂度
O
(
n
log
n
)
O(n\log n)
O(nlogn)。所以总复杂度也为
O
(
n
log
n
)
O(n\log n)
O(nlogn)。
5. Round #806 G
可以很快的写出一个 O ( n 2 ) O(n^2) O(n2) 的 dp,但是没啥用。
发现性质:最优解必定是用好钥匙开前面多少个箱,其它用坏钥匙开。即不存在一个使用好钥匙开的箱子,前面有箱子用坏钥匙开。
然后计算出一个 g g g 数组, g i g_i gi 表示第 i ∼ n i\sim n i∼n 号箱子全都用坏钥匙开能获得的金币数。答案即为:
max i = 0 n ( ∑ j = 1 i a j + g i + 1 ) \max\limits_{i=0}^n \left(\sum_{j=1}^i a_j + g_{i+1}\right) i=0maxn(j=1∑iaj+gi+1)
6. Round #817 G
首先,因为 a xor 0 = a a\operatorname{xor} 0=a axor0=a,所以对于奇数的情况,可以转换为偶数的情况再在后面加一个 0 0 0。
可以发现, a xor ( 2 k − 1 − a ) = 2 k − 1 a\operatorname{xor}(2^{k}-1-a)=2^k-1 axor(2k−1−a)=2k−1,因为 a a a 和 2 k − 1 − a 2^{k}-1-a 2k−1−a 在二进制位下的每一位都不同。所以我们设 p = 2 28 − 1 p=2^{28}-1 p=228−1(这里的指数可以改成别的数,但尽量大一些),构造序列 1 , 2 , p − 1 , p − 2 , 3 , 4 , p − 3 , p − 4 , . . . 1,2,p-1,p-2,3,4,p-3,p-4,... 1,2,p−1,p−2,3,4,p−3,p−4,... 即可。
若序列的长度不是 4 4 4 的倍数,序列末尾还空出了两个,怎么办?可以放两个相等的数,然后第一个加上个 2 30 − 1 2^{30}-1 230−1,再让序列的第二个元素也加上 2 30 − 1 2^{30}-1 230−1 即可(这里的指数也是可以改的)。
程序的大致思路和本文相似,但是细节方面有些不同。