题目大意:给出两个系数表达式,求卷积。
这是一道fft板子题。讲一下fft为什么叫(fast_fast_tle):
正常的系数相乘的时间复杂度为O(n^2),应该不需要证明。
但是某位神犇想出了一个强大的套路:
1.系数表达式->点值表达式;(O(nlogn))
2.点值相乘;(O(n))
3.点值表达式->系数表达式;(O(nlogn))
这样就成O(nlogn)了!
然而前提是fft与单位复数根的结合。
代码:
#include<cmath> #include<cstdio> #include<algorithm> using namespace std; #define N 10000500 int n,m,len=1; struct cp { double x,y; cp(){} cp(double x,double y):x(x),y(y){} }a[N<<1],b[N<<1]; cp operator + (cp a,cp b) { return cp(a.x+b.x,a.y+b.y); } cp operator - (cp a,cp b) { return cp(a.x-b.x,a.y-b.y); } cp operator * (cp a,cp b) { return cp(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x); } int l,r[N<<1],ans[N<<1]; const double Pi = acos(-1.0); void fft(cp *c,int k) { for(int i=0;i<len;i++) if(i<r[i])swap(c[i],c[r[i]]); for(int i=1;i<len;i<<=1) { cp w0(cos(Pi/i),k*sin(Pi/i)); for(int j=0;j<len;j+=(i<<1)) { cp w(1,0); for(int r=0;r<i;r++,w=w*w0) { cp x = c[j+r],y = w*c[j+r+i]; c[j+r] = x+y;c[j+r+i]=x-y; } } } } void conv() { fft(a,1);fft(b,1); for(int i=0;i<=len;i++)a[i]=a[i]*b[i]; fft(a,-1); for(int i=0;i<=n+m;i++)ans[i]=(int)(a[i].x/len+0.5); } int main() { scanf("%d%d",&n,&m); for(int i=0;i<=n;i++)scanf("%lf",&a[i].x); for(int i=0;i<=m;i++)scanf("%lf",&b[i].x); while(len<=n+m)len<<=1,l++;//<= for(int i=0;i<len;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1)); conv(); for(int i=0;i<=n+m;i++)printf("%d ",ans[i]); printf("\n"); return 0; }