多项式真有意思,我超爱多项式。。。
去nm的多项式,然而这个东西还是得学。
多项式位运算(FWT)
是用来解决多项式位运算卷积的工具,支持时间内解决形如之类的运算。
FWT的想法
我们无法快速得知卷积,于是考虑构造一个变换,使得的变换点乘的变换就等于卷积的变换,然后用卷积的变换倒推出卷积。
思路有点类似,只是这里我们利用的是二进制的运算性质,而并非单位根。
or卷积和and卷积
这两个卷积的构造是比较好理解的。
以为例子,我们得到的多项式每一项,所以这个运算就是一个迭代的过程,相当于每次枚举最高位,然后把下标这一位为的迭代到这一位为的上面,因为。
然后考虑一个事实:
设最后要求的多项式为,我们将与点乘,得到的就是:对于一个下标,他的任意两个二进制子集都会进行一次相乘。
考虑这个东西与的关系,会在算位的时候被贡献到中,而也是的子集,所以
又会在的时候被贡献到位。
所以我们得出:
而卷积构造是一致的,基于,基于&,所以迭代的时候把右半部分迭代到左边即可。
xor卷积
这个卷积的构造就很神奇了,好像找不到除了数学归纳法以外的证明。
抛出结论:
这样构造就能数学归纳证明,此时
IFWT
这里相当于是给你了关于的解析式,让你通过算出。
代码实现
1 |
|
原根
定义
定义一个数的原根为一个最小的正整数,满足与互质的同时,满足,且对于
任意,。
性质
对于的原根,的取值互不相同,这是用来的重要标准,另外模数为了能够把长度每次平分成原根的次幂,要求模数的必须含有很多的质因子(至少),如。
求原根
考虑一个很简单的式子,若,那么显然。所以我们没有必要对于检验是否为,只要检验(为的因子)是否为即可,因为任意一个的数必定都是某个的因子,若它做幂是,显然也是。
这样复杂度就是了。
一般因为模数是质数,
题目
SDOI2015序列统计
题目相当于求从集合里选个数,使其乘积在模意义下等于。如果不是乘积而是和的话是很好做的,我们考虑一个多项式,若数在集合中则第项为,否则为,对这个多项式自己卷次,所有项之和就是答案。但是这是乘积,我们考虑变乘法为加法,在模意义下一个很好用的方法就是原根。考虑一个简单的式子:
只要我们找到一个合适的,将中所有数对取对数,然后就可以用加法了,这个数必须满足在模意义下各不相同,显然原根就具有这个性质,并且题目保证是质数且很小,所以原根存在且易求,于是只要转成次幂之后做多项式快速幂即可,注意因为下标实在模意义下进行的,每次乘完之后要把(即)次项及之后的部分并到前面去。
总复杂度
code:
1 |
|
还有一点就是当等于的时候我们不能取对数,但是正好也无法对答案产生贡献,直接判掉即可。
多项式求逆
式子推导
若求出表示模意义下的结果,那么因为显然在模意义下也是,我们就有
于是
乘上
多项式开根
推导与上面类似,依旧是由前半部分推,应该能现场就不写了。
多项式对数函数(ln)
因为求导和积分水平过菜(反正式子也不难背),所以证明咕了。
组合意义
若每一项表示若干个集合加起来凑出的大小为的方案树,那么,且表示集合大小为的方案数,一般来说常数项为,常数项为。
结论
于是就把积分后的多项式和求导后的多项式卷起来再积回去即可。
Code
1 |
|
多项式exp
组合意义
多项式的逆运算,即知道集合大小为的方案数,求取任意个组合成大小为的方案数。
结论
其中表示前半部分做完后的结果,边界。
注意此处是意义下的,所以尽管只有项,也要在意义下做。
Code
1 |
|
我的习惯在最开始把多项式化成的次幂,这样可以避免一些特判,另外要注意两个清零的地方,一个是辅助数组,另一个是多项式乘法之后多出来的后一半,写的时候一定要想一想当前多项式的项数是多少以及每一个多项式运算在模多少的意义下进行。
分治FFT/NTT
用途
处理形如这样的卷积:
因为每一项是和前面的系数相关的,可以用一个类似分治的想法,每次只考虑左边对右边的贡献,然后累加。
考虑一段区间对贡献,他们的下标相差在之间,所以只要把前项拎出来与前半部分做卷积,就可以得到对后半部分的贡献。
Code
1 |
|