https://ac.nowcoder.com/acm/contest/884/B
题目大意就是对于n个集合,每个集合最多32个unsigned int,给出m个询问问对于[l,r]的集合,是否都能各自通过异或得到x。很明显要维护区间线性基的交。
这道题我第一遍做的时候对线性基的理解还不是很深……当时误认为了求出的线性基都只有一个二进制位1,所以合并的时候就直接取与,然后就wa在了百分之六十。后来突然意识到有可能线性基的低位还有1存在,但并未考虑。后来上网查线性基取交的正确做法,给出的那套线代角度的证明实在看不懂,自己想了好久……这里用大白话给出我自己的直观理解。
我们首先要知道,线性基求交的本质是对于两个集合A、B和它们的基baseA、baseB,找到一组基使得既可以通过baseA表达,也可以通过baseB表达。一个通常的想法可以是,这个基脱胎于这两组基中的一组,比如我们对baseB挨个判断是否能被baseA表达,如果可以,这个基就是共有的。这里会有一个问题就是,baseB的低位1并未被完全清除,比如11和01,其实可以产生10这个基,于是我们修改表述为:要求选出baseB中的那些可以被baseA和baseB中低位基共同表达出来的基(等式转化一下就变成了,找出baseB中i和i以下某些基的异或和,这个异或和同样能被baseA表示)。
这里大部分人给出的做法是:在用baseA不断削减baseB中的某个基的同时,如果遇到削减不下去的情况,就把当前值增添到新baseA中(代码中为all),以待后续的基使用,同时记录下来削减到这个地步所需要的baseA(代码中为d),最终,如果某个baseB中的基,能够被一些baseA(在低位baseB的帮助下)削减至0,那么这些baseA的异或值就是一个合法新基,同样用到的baseBi和它的低位“帮手”的异或值也是这个。
1 |
|
其实我自己中间有一种想法就是,预先把所有基中能清理的低位1都清理掉,这样就不用考虑baseB的低位帮手的问题了(有了它也没用)使得merge函数极为简单(注释掉的那个),但后来想到,即使baseB都“净身”,也不排除会有必须和兄弟一起才能表示baseA的情况例如(baseB={1100,0011},baseA={1111})。其实它们是可以共同表示1111这个数字,但在我那个算法中就漏掉了。