2019 HL SC day10
10天都过去了 4天都在全程懵逼。。
怎么可以这么难啊 我服了 现在想起依稀只记得一些结论 什么 反演? 什么后缀自动机?什么组合数的应用?什么神仙东西 ,不过讲课人的确都是神仙。(实名羡慕。
mzx 学长讲的每次都是这么亲民 哇哦 感觉比较舒服的课程 因为比较简单 也给我这个蒟蒻 好好理解了一下指数型生成函数(母函数) 还有一些以前不懂的概念 现在都清晰 了很多了。
多项式 即函数 中附带一个x 的多次幂的东西。卷积 就是两个函数相乘 生成另一个函数的东西。
所以说 这叫做多项式的乘法 当然多项式还有加法 减法 除法 自然除法也是有逆元的 多项式逆元 求出来我们就可以完成操作了。
学长:当发现一个多项式有一点复杂的时候 我们可以求出其逆元 然后 再倒回来 会发现式子变得简单很多。
然后讲了 生成函数和dp 之间的联系 其实我觉得表现形式不太一样剩下的都还好。
ps:学了一发怎样求导 学了一发泰勒展开逼近函数式。
多项式的乘法 也就是 其卷积 复杂度一般为nm 然后FFT 可以优化到(n+m)log(n+m)大致就是这个复杂度。
这样的话对于一类题目 我们把 一些dp 通过生成函数的形式 转换成多项式然后进行多项式乘法快速递推从而推出答案 这是极大的优化。
上午的具体内容就这么多 当然 多项式的化简也很重要 不过一般都是 泰勒展开 逼近 化简 什么的 或者求逆 再倒 这样也能达到化简目的 。注:bzoj 3028 生成函数好题。
现在说一下FFT 吧快速傅里叶变换。。
显然的是 我们直接卷积 是nm 的 这里考虑 利用插值法求出我们的 卷积也就是 生成的另一个函数。那么插值 则需要生成点。
那么我们的DFT 算法就有了 生成点(n+1)个 n^2 合在一起 O(n) 拉格朗日插值快速求 n^2
当然 下午 学长给我们讲了FFT 理解的还行 用到了以前学习的知识总算没有学(这个电脑的输入法都快把我惹火了 受不了)
一些事情 我心情也很不好,别惹我,我会咬人的。 (遇到了老同学 殊途异路 同是天涯沦落人 相逢何必曾相识
FFT DFT 的时候使用复数的单位根 然后 矩阵求逆的时候再次使用单位根 这样 复杂度都是nlogn 所以这也是FFT 的 精妙之处。
首先是求值 显然的是 我们现在是已知系数 一直 自变量 要求 f值 求值得过程 我们将各个系数进行分治 注意这里的递归logn 只是为了求出各个f值而分治的 由单位根可知。
关于 FFT 函数中的东西 我们必须要明白 系数阵*x=值 我们由FFT 的x不断的^2 可以缩小 至其他的x 将会被我们以圆的方式转到。
这便是我对FFT 的理解。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #define db double using namespace std; //FFT author :Chdy const int MAXN=2100010; const db pi=acos(-1.0); int n,m,h,t; struct wy { db v,r; inline wy friend operator +(const wy x,const wy y){return (wy){x.v+y.v,x.r+y.r};} inline wy friend operator -(const wy x,const wy y){return (wy){x.v-y.v,x.r-y.r};} inline wy friend operator *(const wy x,const wy y){return (wy){x.v*y.v-x.r*y.r,x.r*y.v+y.r*x.v};} }a[MAXN],b[MAXN],tmp[MAXN]; int R[MAXN]; inline void FFT(wy *a,int len,int f) { if(len==1)return; for(int i=0;i<len/2;++i) { tmp[i]=a[i<<1]; tmp[i+(len>>1)]=a[i<<1|1]; } for(int i=0;i<len;++i)a[i]=tmp[i]; FFT(a,len>>1,f);FFT(a+(len>>1),len>>1,f); wy wn={cos(2*pi/len),f*sin(2*pi/len)},w={1,0}; for(int i=0;i<len/2;++i) { wy x=a[i],y=w*a[i+len/2]; a[i]=x+y;a[i+len/2]=x-y; w=w*wn; } } int main() { freopen("1.in","r",stdin); ios::sync_with_stdio(false); cin>>n>>m;++n;++m; for(int i=0;i<n;++i)cin>>a[i].v; for(int j=0;j<m;++j)cin>>b[j].v; for(h=t=1;t<(n+m-1);t=t<<1)++h; //for(int i=1;i<t;++i)R[i]= FFT(a,t,1);FFT(b,t,1); for(int i=0;i<t;++i)a[i]=a[i]*b[i]; FFT(a,t,-1); for(int i=0;i<n+m-1;++i)cout<<(int)(a[i].v/t+0.5)<<' '; return 0; }