Educational Codeforces Round 155
[Educational Codeforces Round 155 (Rated for Div. 2)](https://codeforces.com/contest/1879)
D. Sum of XOR Functions
题意
给出一个数列: ,求undefinedsum _{l=1}^{n} \sum _{r=l}^{n}f(l,r) \cdot (r - l + 1)f(l,r) = a_l \oplus a_{l+1} \oplus … \oplus a_r$
答案对取模. ()
思路
我们如果暴力枚举,我们的复杂度就太高了(纯暴力 ,即使使用前缀来优化区间异或的操作,也需要 )。
因此我们需要考虑异或操作的特殊性。
我们可以将a按每个二进制位差分,这样就得到了一个二维数组(设为v),数组的长度是数列中的数的个数,宽度是一个数的二进制位数。
例如样例 对应的v数组为:
| V数组 | 1 | 3 | 2 |
|---|---|---|---|
| undefineda_i >> 1) \& 1$ | 0 | 1 | 1 |
| undefineda_i >> 0) \& 1$ | 1 | 1 | 0 |
然后我们就可以按每次一行的顺序来计算处理,最终将答案按权合并即可。
这样我们每次处理的数据就只有0 和 1,可以用如下方法来在 的时间内解决:
假设我们要处理的01数组为数组b,
设有如下变量:cnt0,cnt1,sum0,sum1,res, 从左向右依次检查每一个数(设下标为1~n):
如果检查到第个数 ,这时候的 cnt0 ,cnt1 分别表示以 为结尾的,区间异或为0 / 为1 的区间 的数量; sum0,sum1 表示以 为结尾的区间异或 的 区间长度的和 , res表示 此时的 前i个数组成的所有异或1区间的 长度和(不止是以i为右边界的区间)
翻译为数学公式即:
然后遍历i 从1 到n:进行状态转移:
如果 :
(原先异或为0的区间再异或1变为1,异或为1的区间再异或为0,效果就是交换cnt0和cnt1)
((区间异或为1的段的数量加上1)
长度都增加了1,相当于总的长度增加了cnt0和cnt1
(最终答案加上 $sum1_i$)
如果b[i] = 0:
(原先的区间异或的值不会变)
(区间异或为0的段的数量加上1)
度都增加了1,相当于总的长度增加了cnt0和cnt1
(最终答案加上 $sum1_i$)
最终将每行得到的res进行按权(第行的权为)相加即可。
代码
1 |
|
