|
2 | 2 |
|
3 | 3 | 我们考虑这样的操作:将所有前缀的XOR_SUM放入一个字典树。这个字典树有31层,对应这整型数字的31个bit。每个节点有一个count属性,记录该节点的子树有个多少叶子节点(即当前有多少个前缀的XOR_SUM经过这个节点)。
|
4 | 4 |
|
5 | | -我们逐个考察前缀sum:假设前i个元素的前缀sum转化为二进制数组是bitsS,k转化为二进制数组是bitsK。那么我们从高到低考察每个bit位j。易知令`b=bitsS[j]^bitsK[j]`,意味着如果某个前缀异或值的第j位是b的话,那么该前缀与[0:i]前缀之间的subarray的异或值到目前为止恰好贴着K。依次类推,我们可以在字典树里从高往低遍历直至叶子节点,判断是有多少个前缀异或值恰好与[0:i]分割出的子区间异或值为k。 |
| 5 | +我们逐个考察每个前缀:假设[0:i]的前缀异或值转化为二进制数组是bitsS,k转化为二进制数组是bitsK。那么我们从高到低考察每个bit位j。易知始终令`b=bitsS[j]^bitsK[j]`,意味着如果某个前缀异或值的第j位是b的话,那么该前缀与[0:i]前缀之间的subarray的异或值到目前为止恰好紧贴着K。依次类推,我们可以在字典树里从高往低遍历直至叶子节点,判断是有多少个前缀恰好与[0:i]分割出的子区间异或值为k。当然也有可能这条路径不存在,意味着没有这样的前缀。 |
6 | 6 |
|
7 | | -除此之外,在上述的字典树的从跟到叶子节点的路径上,如果在某一层`bitsK[j]=0`,那么意味着如果该位置我们不选择上述的`b=bitsS[j]^bitsK[j]`,而是另一个分支`1-b`,那么会导致由此产生的前缀与[0:i]前缀之间的subarray的异或值在第j位上会变成了1,从而大于预期的`bitsK[j]=0`。于是从该分支到其下所有叶子节点的路径也都应该算入符合条件的计数中去。 |
| 7 | +除此之外,在上述的字典树的从跟到叶子节点的路径上,如果在某一层`bitsK[j]=0`,那么意味着如果该位置我们不选择上述的`b=bitsS[j]^bitsK[j]`,而是走另一个分支`1-b`,那么会导致由此访问得到的所有前缀、与[0:i]前缀之间的subarray的异或值在第j位上会变成了1,从而大于预期的`bitsK[j]=0`。于是从该分支到其下所有叶子节点的路径也都应该算入符合条件的计数中去。实际中,对于这种路径,我们直接对结果加上`node->next[1-b]->count`即可,而不用真的去递归遍历到底。 |
8 | 8 |
|
0 commit comments