版权声明:写得不好,转载请通知一声,还请注明出处,感激不尽 https://blog.csdn.net/As_A_Kid/article/details/85006382
最近复习重新学习了一下FWT,然后做了一些乱七八糟的题目。。
注:下文中的
⊕表示异或符号,
∩代表按位与,
∪代表按位或,带*标记的为好题集
顺便提一下
O(n22n)做子集卷积的方法,即求
H[S]=∑i∪j=S,i∩j=0F[i]G[j]。为了保证交起来为空集,枚举
F,G的元素个数
a,b,FWT之后只取元素个数为
a+b的值。
HDU5909 Tree Cutting
HDU
对于一个选择方案,我们仅在深度最小的那个节点上计算。设
f[i][x]表示i号节点上,异或和为x的方案数。不难得到转移方程:
f[u][i]=∑j⊕kf[u][j]∗f[v][k]
用fwt优化之。
时间复杂度
O(nvlogv)
BZOJ4589 Hard Nim
BZOJ
不难想到用
f[x]表示局面异或和为x的方案数,每堆石子都是等价的,所以就是n次方,快速幂即可
时间复杂度
O(mlogmlogn)
Codeforces 662C*
Codeforces
一道还挺有意思的题。注意到n很小,所以考虑把每一列上的数状压成一个整数。如果我们枚举了一个行的异或方案,那么每一列上就有唯一确定的权值,即要么全选0,要么全选1。考虑一个行的异或方案,就相当于是把每一列xor上一个数。那么我们可以构造
ai表示有多少条列的状态为
i,
bi表示状态i的最小代价。
ans(s)=i⊕s=j∑aibj
由于异或满足交换律,那么有
ans(s)=i⊕j=s∑aibj
用fwt优化之,时间复杂度
O(n2n)
HAOI2015 按位或
BZOJ
首先要说明的一点是我们一般用
S来表示S的补集。
可以考虑min-max容斥,然后我们要求的就是
A[S]=∑S∩TP[T]
但是这个不好限制转化一下,考虑到
∑P[S]=1,那么就有
A[S]=1−∑T⊆SP[T]。后面的做一遍高维前缀和即可
时间复杂度
O(n2n)
SPOJ kosare
鉴于spoj老挂,所以洛谷
用
F[S]表示选取的盒子并起来是S的子集的方案数,那么就可以子集反演得到恰好为S的子集的方案数。
设
f[S]为盒子为S的子集的方案数,
F[s]=2f[S]−1,
f用高维前缀和搞一搞即可。
由于最后只询问一个值,可以不必做子集反演,可以
O(n)地扫一遍。
时间复杂度
O(m2m+n)
SPOJ TLE
洛谷
用
f[x]表示考虑了前i个且以x结尾的方案数。不难得到转移方程
f[i]=∑i∩j=0f[j]=∑j⊆if[j]
每次转移完暴力清空掉
c[i]倍数的方案即可。
时间复杂度
O(nm2m+nm)
hihocoder1496 寻找最大值*
hihocoder
一道还挺有意思的题目,可以考虑枚举
i∩j的值
k,那么我们就需要知道最优的
i,j,那么当然是选最大的。
因为我们难以保证
i∩j=k,不妨放缩条件,维护
k的超集中的最大和次大值。这样显然不会漏掉最大值,而也不可能有一个不合法的解超过最优值,因为这个不合法的解的
k肯定偏小,那么必定存在一个相应的合法的解比它更大。
枚举超集用高维前缀和解决。
时间复杂度
O(vlogv)