BZOJ2194: 快速傅立叶之二
【传送门:BZOJ2194】
简要题意:
给出位置为0到n-1的a数组和b数组,定义$C[k]=\sum_{k<=i<n}a[i]*b[i-k]$,求出C数组
题解:
题目即正解系列
将这个式子变为$C[k]=\sum_{i=k}^{n-1}a[i]*b[i-k]$
要使得为卷积形式,就将b倒过来,设$b'[i]=b[n-1-i]$
得到$C[k]=\sum_{i=k}^{n-1}a[i]*b'[n-1-i+k]$
这样子就可以用FFT求卷积了,所有输出n-1到2n-2的数就行了
参考代码:
#include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> using namespace std; const double PI=acos(-1.0); struct Complex { double r,i; Complex(){} Complex(double _r,double _i){r=_r;i=_i;} friend Complex operator + (const Complex &x,const Complex &y){return Complex(x.r+y.r,x.i+y.i);} friend Complex operator - (const Complex &x,const Complex &y){return Complex(x.r-y.r,x.i-y.i);} friend Complex operator * (const Complex &x,const Complex &y){return Complex(x.r*y.r-x.i*y.i,x.r*y.i+x.i*y.r);} }a[410000],b[410000]; int R[410000]; int n; void fft(Complex *y,int len,int on) { for(int i=0;i<len;i++) if(i<R[i]) swap(y[i],y[R[i]]); for(int i=1;i<len;i<<=1) { Complex wn(cos(PI/i),sin(on*PI/i)); for(int j=0;j<len;j+=(i<<1)) { Complex w(1,0); for(int k=0;k<i;k++,w=w*wn) { Complex u=y[j+k]; Complex v=w*y[j+k+i]; y[j+k]=u+v; y[j+k+i]=u-v; } } } if(on==-1) for(int i=0;i<=len;i++) y[i].r/=len; } void calc(int n) { int L=0,m=2*n; for(n=1;n<=m;n<<=1) L++; memset(R,0,sizeof(R)); for(int i=0;i<n;i++) R[i]=(R[i>>1]>>1)|(i&1)<<(L-1); fft(a,n,1); fft(b,n,1); for(int i=0;i<=n;i++) a[i]=a[i]*b[i]; fft(a,n,-1); } int main() { scanf("%d",&n);n--; for(int i=0;i<=n;i++) scanf("%lf%lf",&a[i].r,&b[n-i].r); calc(n); for(int i=n;i<=2*n;i++) printf("%d\n",int(a[i].r+0.5)); return 0; }
渺渺时空,茫茫人海,与君相遇,幸甚幸甚