BZOJ2179 - FFT快速傅立叶

本文介绍了一种使用多项式乘法和快速傅立叶变换(FFT)来实现大数相乘的方法,该方法的时间复杂度为O(nlogn),适用于处理大规模数据运算。通过将大数转换为多项式,利用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.

名字暴露一切

转载于:https://www.cnblogs.com/VisJiao/p/BZOJ2179.html

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值