码迷,mamicode.com
首页 > 其他好文 > 详细

【BZOJ】2194: 快速傅立叶之二

时间:2018-02-05 17:02:43      阅读:155      评论:0      收藏:0      [点我收藏+]

标签:wap   printf   没有   code   pos   技术分享   span   while   处理   

【题意】请计算C[k]=sigma(a[i]*b[i-k]) 其中 k < = i < n ,并且有 n < = 10 ^ 5。 a,b中的元素均为小于等于100的非负整数。

【算法】快速傅里叶变换(FFT)处理卷积

【题解】题意要求C[k]=ΣA[i]*B[i-k],i=k~n-1。

即C[k]=ΣA[i+k]*B[i],i=0~n-k-1。

这是差为定值的情况,将其中一个向量反转即可得到和为定值的卷积形式。

令B[i]=B[n-i-1]

C[k]=ΣA[i+k]*B[n-i-1],i=0~n-k-1。

和为n+k-1,根据卷积D[n+k-1]=ΣA[i+k]*B[n-i-1],i=0~n-k-1。

当i=[n-k,n+k-1]时,A[i+k]=0,所以没有影响。

用FFT处理卷积D即可。

最后C[0~n-1]对应D[n-1~2*n-2]。

复杂度O(n log n)。

技术分享图片
#include<cstdio>
#include<algorithm>
#include<complex>
#include<algorithm>
using namespace std;
const int maxn=300010;
const double PI=acos(-1);
int n,b1[maxn],b2[maxn];
complex<double>a1[maxn],a2[maxn];
namespace fft{
    complex<double>o[maxn],oi[maxn];
    void init(int n){
        for(int k=0;k<n;k++)o[k]=complex<double>(cos(2*PI*k/n),sin(2*PI*k/n)),oi[k]=conj(o[k]);
    }
    void transform(complex<double>*a,int n,complex<double>*o){
        int k=0;
        while((1<<k)<n)k++;
        for(int i=0;i<n;i++){
            int t=0;
            for(int j=0;j<k;j++)if((1<<j)&i)t|=(1<<(k-j-1));
            if(i<t)swap(a[i],a[t]);
        }
        for(int l=2;l<=n;l*=2){
            int m=l/2;
            for(complex<double>*p=a;p!=a+n;p+=l){
                for(int i=0;i<m;i++){
                    complex<double>t=o[n/l*i]*p[i+m];
                    p[i+m]=p[i]-t;
                    p[i]+=t;
                }
            }
        }
    }
    void dft(complex<double>*a,int n){transform(a,n,o);}
    void idft(complex<double>*a,int n){transform(a,n,oi);for(int i=0;i<n;i++)a[i]/=n;}
}
void multply(){
    int N=1;
    while(N<n+n)N*=2;
    fft::init(N);fft::dft(a1,N);fft::dft(a2,N);
    for(int i=0;i<N;i++)a1[i]*=a2[i];
    fft::idft(a1,N);
}
int main(){
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d%d",&b1[i],&b2[i]);
        a1[i].real(b1[i]);a2[n-i-1].real(b2[i]);
    }
    multply();
    for(int i=n-1;i<2*n-1;i++)printf("%d\n",(int)((floor)(a1[i].real()+0.5)));
    return 0;
}
View Code

 

【BZOJ】2194: 快速傅立叶之二

标签:wap   printf   没有   code   pos   技术分享   span   while   处理   

原文地址:https://www.cnblogs.com/onioncyc/p/8418113.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!