黎明前的巧克力
题意
选出长度为
n 的序列
a 中的两个可空不交子序列,使得这两个子序列的异或和相等。
0≤ai<2V。
做法
考虑集合幂级数。我们要选出一个子序列,这个子序列的异或和为
0,子序列内部的数可以选择选入第一个子序列或者第二个子序列。
不难发现这是在求
[x0]i=1∏n(1+2xai)。
由于 FWT 的性质不足,考虑一种暴力也就是做
n 次 FWT 后点乘再 IFWT。
考虑 FWT 的定义式:
F^i=j=0∑2V−1Fj(−1)i∩j。
容易发现对
1+2xai 做 FWT 后只有两种数也就是
−1 和
3。
考虑点乘后的,IFWT 前的序列中,每一项的贡献为
(−1)z3n−z。
考虑算出
z。我们把所有
ai 放到一个序列
b 中做 FWT,根据
b^i 的值算出
zi 即可。
总结
我的 XOR 卷积人生
题意
你要在两个长度为
2n 的矩阵序列上做 xor 卷积,没有任何手段获取乘法逆元。
要求为
O(n22n)。
Part 1
对于序列
[a0,a1] 与
[b0,b1] 做异或卷积可以得到
[a0b0+a1b1,a0b1+a1b0]。
考虑如何把这个过程拆分成点乘。
设计一个形式元
x,计算
(a0+a1x)(b0+b1x)。
得到的结果是
a0b0+a1b0x+a0b1x+a1b1x2。
我们想要的结果是
f(x)=a0b0+a1b0x+a0b1x+a1b1。
朴素的做法是设计
x2=1,然后让
x=1,−1。这两个根为
α,β。
求出
f(α),f(β) 后再插值还原
f。
Part 2
对于
n 为任意的情况。我们设计
xS 表示
i∈S∏xi。所以
x 其实是一个长度为
n 的向量
[x0,x1,...,xn−1]。
设计集合幂级数
f(x)=i=0∑2n−1Aixi。
我们再设计
2n 个根
Xp。定义
Xp=i=0∏n−1[pi=0]α+[pi=1]β。
代入这些根后得到
2n 个结果
Yp=f(Xp)。代入根的过程容易用分治加速。
对于 xor 卷积,要解方程
x2=1,根是
α=1,β=−1。
对于 or 卷积,要解方程
x2=x,根是
α=0,β=1。
Part 3
考虑子集卷积。
要解的方程是
x2=0,这是重根,无法插值。
设根为
α=0,β=ϵ。维护含有
ϵ 的多项式即可。
插值时可以求逆。具体的,我们让
Y0=f(0),Y1=f(ϵ)。
拉格朗日插值得到
Y0X0−X1x−X1+Y1X1−X0x−X0。容易求解。
最后得到答案后再让
ϵ←0 即可。
Part 4
我们让原题的
α=1,β=ϵ−1。
此时要做多项式操作,复杂度变为
O(n32n)。
Part 4.5
不妨把
x 平移一位,也就是
a0+a1(x+1−1)。我们让
a0←a0+a1,这样变成
a0+a1(x−1)。
这个时候我们让
(x−1)2=1,解得
α=0,β=2。
我们设
β=ϵ,跑一遍子集卷积,最后再让
ϵ←2 即可。最后再还原真正的
c0,c1。
时间复杂度可以复用子集卷积的实现得到
O(n22n)。
总结
这个题把 FWT 看成了一种多项式多点求值方法,把 IFWT 看成了一种多项式插值方法。是一道不可多得的好题。
3^N Minesweeper
题意
做法
我们来考虑用矩阵表示 FWT。
一般来讲,FWT 可以看成
F^i=j=0∑3n−1c(j,i)Fj。
然后我们要对这个矩阵
c 求逆来得到逆变换(IFWT)。
考虑拆出一个
3×3 的矩阵
c0 表示
n=1 时的矩阵。
c1 表示
c0 的逆矩阵。
那么我们把
c(j,i) 表示成
v=0∏n−1c0(jv,iv)。
接下来证明
c−1(j,i)=v=0∏n−1c1(jv,iv):
Fi=j=0∑3n−1c−1(j,i)k=0∑3n−1c(k,j)FkFi=j=0∑3n−1(v=0∏n−1c1(jv,iv))k=0∑3n−1(v=0∏n−1c0(kv,jv))FkFi=k=0∑3n−1j=0∑3n−1(v=0∏n−1c1(jv,iv))(v=0∏n−1c0(kv,jv))FkFi=k=0∑3n−1j=0∑3n−1I(k,j)I(j,i)Fk
这个显然成立。由于逆矩阵如果存在就唯一所以得解。
考虑快速计算。接下来我们引入 FWT 的矩阵形式。
F^i=j=0∑3n−1c(j,i)FjF^i=j=0∑3n−1(v=0∏n−1c0(jv,iv))FjF^i=j=0∑3n−1−1c0(0,in−1)(v=0∏n−2c0(jv,iv))Fj+j=3n−1∑2×3n−1−1c0(1,in−1)(v=0∏n−2c0(jv,iv))Fj+j=2×3n−1∑3n−1c0(2,in−1)(v=0∏n−2c0(jv,iv))Fj
考虑预处理
Fi′=j=0∑3n−1(v=0∏n−2c0(jv,iv))[jn−1=in−1]Fj。
这样可以得到
F^i=c0(0,iv)Fa′+c0(1,iv)Fb′+c0(2,iv)Fc′。其中
a,b,c 为改变
i 的位
n−1 变为
0/1/2 后得到的三进制数。这就是 FWT。
总结
矩阵形式的 FWT 可以用来描述一些更一般的问题。
欧伊昔说了任意运算表的情况,但我不会。其实大概意思就是把每一维拆成更多矩阵但是先不写了。
集合划分计数
题意
在长度为
m 的序列
a 中选至多
k 个
[0,2n−1] 的二进制数使得他们两两的按位与为
0,按位或为
2n−1。
做法
弱化问题是“不交并”集合幂级数的
exp。这也是最常说是集合幂级数的运算。
先理解一下
O(n22n) 做
exp 这件事情。
我们设计了一个新的元
y。这其实就是之前说的
ϵ。
但是现在换个角度,我们先对
x 这一维做 or-FWT。
什么意思?就是每一维代入
0 和
1 做点求值就懂了。
这个时候我们
y 这一元一直没有变,所以我们就是做了
n 次 or-FWT,点求值出来其实
1 代表的是当前这个维度的
yi。
这样子我们求完后就要求出
2n 个点值的答案。这就是在
y 这一维上做一遍
exp。
然后我们再 IFWT 回去就好了。
那么这个题就是把里面的那次操作改了一下。
总结
可以逐点牛顿迭代法,但我不会。
FWT + IFWT 是一种插值方法,这个东西是有用且直观的。
总结
好多难的东西还没写,但是新年快乐!