HDU1402 A * B Problem Plus[FFT]

题意:

计算A*B(A,B均不超过5e4位)。


题解:

计算A*B 可以把AB的各项化成多项式来相乘

把这两个多项式相乘起来就能得到A*B的结果了。

用FFT可以快速的求出两多项式相乘的结果,然后就可以得到每一位的的结果。

求得A*B的结果之后,做进位处理。

注意最后要去掉前导零,然后倒着输出。

这是第一次写的FFT的题目,所以代码上面有对模版的一些解释。



#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<vector>
using namespace std;
typedef long long ll;
const double PI=acos(-1.0);
const int N=5e4+5;
const int M=(1<<17)+5;//取大于2*N的2的幂
char A[N],B[N];
int ans[M];
struct Complex
{
    double real,image;
    Complex(double r=0.0,double i=0.0):real(r),image(i){};
    Complex operator + (const Complex &b)
    {
        return Complex(real+b.real,image+b.image);
    }
    Complex operator - (const Complex &b)
    {
        return Complex(real-b.real,image-b.image);
    }
    Complex operator * (const Complex &b)
    {
        return Complex(real*b.real-image*b.image,image*b.real+real*b.image);
    }
    Complex operator / (const Complex &b)
    {
        double r=(real*b.real+image*b.image)/(b.real*b.real+b.image*b.image);
        double i=(image*b.real-real*b.image)/(b.real*b.real+b.image*b.image);
        return Complex(r,i);
    }
}a[M],b[M];
/*
将当前项跟其二进制的倒序交换
倒序过程中
k的初始值是len/2 即可取的二进制的最高位
只有当j比当前的k要大,代表有进位,所以减去后
最后在j<k的时候,补上进位
*/
void change(Complex x[],int len)
{
    //0跟最后二进制全1的都不用处理,所以是len-1
    for (int i=1 , j=len/2 ; i<len-1 ; ++i)
    {
        if (i<j)
            swap(x[i],x[j]);
        //只有i比j小的时候交换,避免重复交换导致交换无效
        int k=len/2;
        while (j>=k)
        {
            j-=k;
            k/=2;
        }
        if (j<k)
            j+=k;
    }
}
/*
dft=1时是DFT dfs=-1时是逆DFT
len必须是2的幂
*/
void FFT(Complex x[],int len,int dft)
{
    change(x,len);
    for (int h=2 ; h<=len ; h<<=1)
    {
        Complex wn(cos(dft*2*PI/h),sin(dft*2*PI/h));
        for (int j=0 ; j<len ; j+=h)
        {
            Complex w(1,0);//旋转因子
            for (int k=j ; k<j+h/2 ; ++k)
            {
                Complex u=x[k];
                Complex t=w*x[k+h/2];
                x[k]=u+t;
                x[k+h/2]=u-t;
                w=w*wn;
            }
        }
    }
    if (dft==-1)
    {
        for (int i=0 ; i<len ; ++i)
        {
            x[i].real/=len;
            x[i].image/=len;
        }
    }
}
int main()
{
	while (~scanf("%s%s",A,B))
    {
        int lena=strlen(A),lenb=strlen(B);
        int len=1;
        /*得到最长的2*n*/
        while (len<lena*2 || len<lenb*2)
            len<<=1;
        /*将每一位拆开*/
        for (int i=0 ; i<len ; ++i)
        {
            if (i<lena)
                a[i]=Complex(A[lena-1-i]-'0',0);
            else
                a[i]=Complex(0,0);
            if (i<lenb)
                b[i]=Complex(B[lenb-1-i]-'0',0);
            else
                b[i]=Complex(0,0);
        }
        //DFT
        FFT(a,len,1);
        FFT(b,len,1);
        for (int i=0 ; i<len ; ++i)
            a[i]=a[i]*b[i];
        //DFT-1
        FFT(a,len,-1);
        memset(ans,0,sizeof(ans));
        for (int i=0 ; i<len ; ++i)
            ans[i]=(int)(a[i].real+0.5);//四舍五入取整
        for (int i=0 ; i<len ; ++i)
        {
            ans[i+1]+=ans[i]/10;//进位
            ans[i]%=10;
        }
        while (!ans[len] && len>0)
            len--;
        for (int i=len ; i>=0 ; --i)
            printf("%d",ans[i]);
        printf("\n");
    }
	return 0;
}








  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值