zoukankan      html  css  js  c++  java
  • ACM学习历程—51NOD1028 大数乘法V2(FFT)

    题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1028

    题目大意就是求两个大数的乘法。

    但是用普通的大数乘法,这个长度的大数肯定不行。

    大数可以表示点值表示法,然后卷积乘法就能用FFT加速运算了。

    这道题是来存模板的。

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #define LL long long
    
    using namespace std;
    
    //多项式乘法运算
    //快速傅里叶变换
    //FFT
    //用于求两个多项式的卷积,但有精度损失
    //时间复杂度nlogn
    const int maxN = 400005;
    const double PI = acos(-1.0);
    
    struct Complex
    {
        double r, i;
    
        Complex(double rr = 0.0, double ii = 0.0)
        {
            r = rr;
            i = ii;
        }
    
        Complex operator+(const Complex &x)
        {
            return Complex(r+x.r, i+x.i);
        }
    
        Complex operator-(const Complex &x)
        {
            return Complex(r-x.r, i-x.i);
        }
    
        Complex operator*(const Complex &x)
        {
            return Complex(r*x.r-i*x.i, i*x.r+r*x.i);
        }
    };
    
    //雷德算法--倒位序
    //Rader算法
    //进行FFT和IFFT前的反转变换。
    //位置i和 (i二进制反转后位置)互换
    void Rader(Complex y[], int len)
    {
        int j = len>>1;
        for(int i = 1; i < len-1; i++)
        {
            if (i < j) swap(y[i], y[j]);
            int k = len >> 1;
            while (j >= k)
            {
                j -= k;
                k >>= 1;
            }
            if (j < k) j += k;
        }
    }
    
    //FFT实现
    //len必须为2^k形式,
    //on==1时是DFT,on==-1时是IDFT
    void FFT(Complex y[], int len, int on)
    {
        Rader(y, len);
        for (int h = 2; h <= len; h<<=1)//分治后计算长度为h的DFT
        {
            Complex wn(cos(-on*2*PI/h), sin(-on*2*PI/h)); //单位复根e^(2*PI/m)用欧拉公式展开
            for (int j = 0; j < len; j += h)
            {
                Complex w(1, 0);//旋转因子
                for (int k = j; k < j+h/2; k++)
                {
                    Complex u = y[k];
                    Complex 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;
    }
    
    //求卷积
    void Conv(Complex a[], Complex b[], int ans[], int len)
    {
        FFT(a, len, 1);
        FFT(b, len, 1);
        for (int i = 0; i < len; i++)
            a[i] = a[i]*b[i];
        FFT(a, len, -1);
        //精度复原
        for(int i = 0; i < len; i++)
            ans[i] = a[i].r+0.5;
    }
    
    //进制恢复
    //用于大数乘法
    void turn(int ans[], int len, int unit)
    {
        for(int i = 0; i < len; i++)
        {
            ans[i+1] += ans[i]/unit;
            ans[i] %= unit;
        }
    }
    
    char str1[maxN], str2[maxN];
    Complex za[maxN],zb[maxN];
    int ans[maxN];
    int len;
    
    void init(char str1[], char str2[])
    {
        int len1 = strlen(str1);
        int len2 = strlen(str2);
        len = 1;
        while (len < 2*len1 || len < 2*len2) len <<= 1;
    
        int i;
        for (i = 0; i < len1; i++)
        {
            za[i].r = str1[len1-i-1]-'0';
            za[i].i = 0.0;
        }
        while (i < len)
        {
            za[i].r = za[i].i = 0.0;
            i++;
        }
        for (i = 0; i < len2; i++)
        {
            zb[i].r = str2[len2-i-1]-'0';
            zb[i].i = 0.0;
        }
        while (i < len)
        {
            zb[i].r = zb[i].i = 0.0;
            i++;
        }
    }
    
    void work()
    {
        Conv(za, zb, ans, len);
        turn(ans, len, 10);
        while (ans[len-1] == 0) len--;
        for (int i = len-1; i >= 0; i--)
            printf("%d", ans[i]);
        printf("
    ");
    }
    
    int main()
    {
        //freopen("test.in", "r", stdin);
        while (scanf("%s%s", str1, str2) != EOF)
        {
            init(str1, str2);
            work();
        }
        return 0;
    }
    View Code
  • 相关阅读:
    DataTable.Load技巧,多结果集查询
    sql编写小技巧
    最近学习记录
    分享layui的table的一些小技巧,前端分页
    WTM框架在开发过程中如何动态迁移表和创建表
    .net core cookie滑动过期设置
    在使用DapperExtensions时遇到"其他信息: ConnectionString 属性尚未初始化。"错误
    在域环境中客户端三次输入密码错误锁定方法(原创)
    共享打印机提示0x000006cc的解决方法
    win10 1909版本用ultraISO做启动U盘,写入只有1g不到
  • 原文地址:https://www.cnblogs.com/andyqsmart/p/4972986.html
Copyright © 2011-2022 走看看