【数论】hdu1402 A * B Problem Plus(FFT)

6 篇文章 0 订阅

题意:

大数相乘


题解:

由于题范围为10^5;大数据模拟复杂度为O(n^2),需要用FFT实现快速乘。


FFT的原理参考了下方博客:

http://blog.miskcoo.com/2015/04/polynomial-multiplication-and-fast-fourier-transform#mjx-eqn-IDFT-equation


模板(kuangbin):

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <string>
using namespace std;
#define MAXN 200010
const double PI = acos(-1.0);

//复数结构体
struct cop_num
{
    double r,i;
    cop_num(double _r=0.0,double _i=0.0)
    {//初始化
        r=_r;i=_i;
    }

    //重载运算符
    cop_num operator +(const cop_num &b)
    {
        return cop_num(r+b.r,i+b.i);
    }

    cop_num operator -(const cop_num &b)
    {
        return cop_num(r-b.r,i-b.i);
    }

    cop_num operator *(const cop_num &b)
    {
        return cop_num(r*b.r-i*b.i,r*b.i+i*b.r);
    }
};

cop_num x1[MAXN],x2[MAXN];
string str1,str2;
int sum[MAXN];

//反转变换
void change(cop_num y[],int len)
{
    int i,j,k;
    for(int i=1,j=len/2;i<len-1;i++)
    {
        if(i<j) swap(y[i],y[j]);
        k=len/2;
        while(j>=k)
        {
            j-=k;
            k/=2;
        }
        if(j<k) j+=k;
    }
}

//on=1时DFT,-1时IDFT
void fft (cop_num y[],int len,int on)
{
    change(y,len);
    for(int h=2;h<=len;h<<=1)
    {
        //wn打表
        cop_num wn(cos(-on*2*PI/h),sin(-on*2*PI/h));
        for(int j=0;j< len;j+=h)
        {
            cop_num w(1,0);
        for(int k=j;k< j+h/2;k++)
        {
            cop_num u=y[k];
            cop_num t=w*y[k+h/2];
            y[k] = u+t;
            y[k+h/2] = u-t;
            w = w*wn;
        }
        }
    }
    if(on==-1)
     for(int i=0;i< len;i++)
            y[i].r/=len;
}

int main()
{

while(cin>>str1>>str2)
{
    int len1=str1.length();
    int len2=str2.length();
    int len=1;
    while(len <len1*2|| len< len2*2) len<<=1;
    for(int i=0;i<len1;i++)
    x1[i]=cop_num(str1[len1-1-i]-'0',0);

    //长度为2^K,原长度不足则补0
    for(int i=len1;i<len;i++)
    x1[i]=cop_num(0,0);

    for(int i=0;i<len2;i++)
    x2[i]=cop_num(str2[len2-1-i]-'0',0);
    for(int i=len2;i<len;i++)
    x2[i]=cop_num(0,0);

    //DFT
    fft(x1,len,1);
    fft(x2,len,1);
    for(int i=0;i<len;i++)
        x1[i]=x1[i]*x2[i];
    fft(x1,len,-1);

for(int i=0;i<len;i++)
    sum[i]=(int) (x1[i].r+0.5);
for(int i=0;i<len;i++)
{
    sum[i+1]+=sum[i]/10;
    sum[i]%=10;
}

//去前导0
len =len1+len2-1;
while(sum[len]<=0&&len > 0) len--;

for(int i=len;i>=0;i--)
    printf("%d",sum[i]);
    cout<<endl;
}
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值