BZOJ2179 - FFT快速傅立叶

Portal

Description

给出两个\(n(n\leq6\times10^4)\)位的正整数\(x,y\),求\(x\times y\)

Solution

\(a_i,b_i\)分别表示\(x,y\)从低到高的第\(i\)位,\(f_1(x)=\sum_{i=0}^{n-1}a_ix^i,f_2(x)=\sum_{i=0}^{n-1}b_ix_i\)。则\(x=f_1(10),y=f_2(10)\)。做多项式乘法并进位即可。

时间复杂度\(O(nlogn)\)

Code

//FFT快速傅立叶
#include <complex>
#include <cstdio>
using namespace std;
typedef complex<double> cpx;
int const N=2e5+10;
double const PI=acos(-1);
int n,t; char s[N];
cpx a[N],b[N],c[N];
int pos[N];
void FFT(cpx x[],int f)
{
    for(int i=0;i<t;i++) if(i<pos[i]) swap(x[i],x[pos[i]]);
    for(int i=1;i<t;i<<=1)
    {
        cpx Wn=cpx(cos(PI/i),f*sin(PI/i));
        for(int j=0;j<t;j+=i<<1)
        {
            cpx w=1;
            for(int k=0;k<i;k++,w*=Wn)
            {
                cpx p=x[j+k],q=w*x[j+k+i];
                x[j+k]=p+q,x[j+k+i]=p-q;
            }
        }
    }
    if(f==-1) for(int i=0;i<t;i++) x[i]/=t;
}
int ans[N];
int main()
{
    scanf("%d",&n);
    scanf("%s",s); for(int i=0;i<n;i++) a[i]=s[n-i-1]-'0';
    scanf("%s",s); for(int i=0;i<n;i++) b[i]=s[n-i-1]-'0';
    t=1; int n0=0; while(t<=n+n) t<<=1,n0++;
    for(int i=0;i<t;i++) pos[i]=(pos[i>>1]>>1)|((i&1)<<(n0-1));
    FFT(a,1),FFT(b,1);
    for(int i=0;i<t;i++) c[i]=a[i]*b[i];
    FFT(c,-1);
    for(int i=0;i<t;i++) ans[i]=(int)(c[i].real()+0.5);
    for(int i=0;i<t;i++) ans[i+1]+=ans[i]/10,ans[i]%=10;
    while(!ans[t]) t--;
    for(int i=t;i>=0;i--) printf("%d",ans[i]);
    puts("");
    return 0;
}

P.S.

名字暴露一切

posted @ 2018-03-20 14:23  VisJiao  阅读(146)  评论(0编辑  收藏  举报