为什么突然学这个 发现有题不会做了。
引子 n个数字中求任意两个数字的或最大.n<=100000 值域[1,1<<20].
标签是动态规划 但是我不知道咋搞,只能从多项式的角度来考虑这个问题。
给出n个数字 我们在其对应位置a[x]=1 表示当前数字出现过 那么这个问题其实就是值域乘值域的卷积 不过数组的下标的运算不是相加而是相或
进一步的 设$Ck=Ai*Bj(i|j==k)$我要求出这个式子 最后看最大的那个不为0的位置k就是答案了。
有意思的是 这和FFT如出一折 不过就是数组下标的运算变了。
如果我们能像FFT那样快速求出C这个多项式的话我们也同时可以快速求得答案了。
于是我们考虑构造一个 多项式的运算 FWT_or运算 使得 FWT_or(A) $cdot$ FWT_or(B)=FWT_or(C)
观察这个等式我们需要做的是 快速得到FWT_or(A) 和 FWT_or(B)的值 然后进行O(n)的乘法得到FWT_or(C) 最后再通过逆运算反带出C这个多项式。
接下来论述这三个过程怎么搞为什么是对的
我们构造出了的这个FWT_or是有特点的以至于能和真正的暴力卷积出的结果C的FWT_or刚好对的上我想你懂我的意思
怎么想出来的不再赘述 具体的说一下FWT_or(A)=?设其等于A' 那么$A'[i]=sum{A[j]}_{i|j==i}$
先不说怎么求出这个FWT_or(A) 先说明 FWT_or(A) $cdot$ FWT_or(B)=FWT_or(C) 其中$Ck=A[i]*B[j](i|j==k)$这个等式的正确性
注意中间这个点积的意思是A[i]*B[j](i==j)所以这一步的复杂度和FFT是一致的O(n).
证明1:感性理解。大家思考一会就发现了吧 确实是正确的。
证明2:学术证明到百度。这里不再赘述.
至此我们证明了这个等式是对的考虑如何求出FWT_or(A) 以及FWT_or的逆运算怎么搞。
这个FWT_or我们不可能再去枚举子集太浪费时间考虑分治(二进制有关的东西一般都分治考虑...
设A0为A的前一半 A1为A的后一半 如果A的长度为2^k(就算不是 强行加到这个长度就行了) 那么这两半分别为$2^{k-1}$
递归处理这两半 既然是递归的过程我们知道终点了吧?当k==0时 长度为1那么显然就是他本身。
至此我们已经知道了FWT(A0) 和 FWT(A1) 如何导出 FWT(A) 显然对于FWT(A) 对于A的前一半是没有任何影响的依然是FWT(A0)
后一半会受到前一半的影响导致每个点的点值变大进一步的其实就是相当于第k位填了1子集不仅有FWT(A1) 还有FWT(A0)
FWT(A)=merge(FWT(A0),FWT(A0)+FWT(A1)); 求出来了merge的意思是指将前后两个地方直接拼起来。
也就是说我们可以求出FWT(C)了 如何导出 C这个多项式呢?其实就是UFWT(C)
反着做这个过程就行了 我们已知FWT(C)=merge(FWT(C0),FWT(C0)+FWT(C1))
也就是说我们再把C分成C0和C1的话 那么C=merge(C0,C1) 我们求出C0和C1即可
C0=UFWT(FWT(C0)) C1=UFWT(FWT(C1)) 还是讨论当k==0时 FWT(C0)=C0; FWT(C1)=C1; 所以此时递归结束
FWT(C0)=FWT(C)的前一半 FWT(C1)=FWT(C)的后一半-FWT(C0)(即C的前一半)
我们得到了这两个等式 递归计算即可.其实和FFT差不太多.
发现求法不太规范 UFWT(C')=merge(UFWT(C0'),UFWT(另一半)-UFWT(C0)).
这样顺眼很多 ..值得一提的是不需要进行递归处理比蝴蝶操作更方便的是 啥都不用干 直接上FFT那套 哦不FWT那套..
按位与跟|差不多一样这里不再赘述..
考虑一下异或 xor->...
我想了2h对着xht37的blog勉强看懂了xor 还是太菜了这里给出链接 具体内容自己理解.
LINK:[xht37的FWT文章](https://www.luogu.com.cn/blog/xht37/solution-p4717)
简要的来说其实就是 FWT_and(A)=merge(FWT_and(A0)+FWT_and(A1),FWT_and(a0)-FWT_and(a1));这还算是比较容易理解
UFWT(A')=merge(U(A0')+U(A1')/2,U(A0)-U(A1')/2)
至此可以撒花了~ FWT 快速沃尔什变换