[BZOJ]2194: 快速傅立叶之二
题目大意:给定序列a,b,求序列c满足c[k]=sigma(a[i]*b[i-k]) (k<=i<n)。(n<=10^5)
思路:观察发现就是普通的卷积反一反(翻转ab其中一个后做卷积,倒着输出即可),FFT模板复习。
#include<cstdio> #include<cmath> #include<algorithm> using namespace std; inline int read() { int x;char c; while((c=getchar())<'0'||c>'9'); for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0'; return x; } #define MN 262144 struct cp { double r,i; cp(double r=0,double i=0):r(r),i(i){} cp operator+(cp b){return cp(r+b.r,i+b.i);} cp operator-(cp b){return cp(r-b.r,i-b.i);} cp operator*(cp b){return cp(r*b.r-i*b.i,r*b.i+i*b.r);} }w[2][MN+5],a[MN+5],b[MN+5],c[MN+5]; const double pi=acos(-1); int N,R[MN+5]; void init(int n) { for(N=1;N<n;N<<=1); int i,j,k;cp g(cos(2*pi/N),sin(2*pi/N)); for(i=w[0][0].r=1;i<N;++i)w[0][i]=w[0][i-1]*g; for(i=w[1][0].r=1;i<N;++i)w[1][i]=w[0][N-i]; for(i=j=0;i<N;R[++i]=j)for(k=N>>1;(j^=k)<k;k>>=1); } void fft(cp*x,int v) { int i,j,k; for(i=j=0;i<N;++i)if(i<R[i])swap(x[i],x[R[i]]); for(i=1;i<N;i<<=1)for(j=0;j<N;j+=i<<1)for(k=0;k<i;++k) { cp p=x[i+j+k]*w[v][N/(i<<1)*k]; x[i+j+k]=x[j+k]-p;x[j+k]=x[j+k]+p; } if(v)for(i=0;i<N;++i)x[i].r/=N,x[i].i/=N; } int main() { int n=read(),i; for(i=0;i<n;++i)a[n-i-1].r=read(),b[i]=read(); init(n<<1);fft(a,0);fft(b,0); for(i=0;i<N;++i)c[i]=a[i]*b[i];fft(c,1); for(i=n;i--;)printf("%d\n",int(c[i].r+0.5)); }